diff --git a/.flowconfig b/.flowconfig index 9b8e5571f73fe..5fa36fee303a7 100644 --- a/.flowconfig +++ b/.flowconfig @@ -5,7 +5,6 @@ .*/node_modules/resolve/test/resolver/malformed_package_json/package.json [options] -as_const=true component_syntax=true module.system=haste module.system.haste.use_name_reducers=true @@ -42,4 +41,4 @@ untyped-import untyped-type-import [version] -^0.253.0 +^0.266.1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a162706e4373..8533dc5a58244 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,10 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.76.0 + # Should stay in sync with fbcode/buck2/rust-toolchain + # And other similar references in this file and + # docusaurus.yml + toolchain: nightly-2024-10-13 override: true - name: "Run tests" run: cargo test --manifest-path=compiler/Cargo.toml --locked ${{ matrix.target.features && '--features' }} ${{ matrix.target.features }} @@ -118,7 +121,10 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.76.0 + # Should stay in sync with fbcode/buck2/rust-toolchain + # And other similar references in this file and + # docusaurus.yml + toolchain: nightly-2024-10-13 override: true - name: "Update fixture tests" run: ./scripts/update-fixtures.sh @@ -178,7 +184,10 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.76.0 + # Should stay in sync with fbcode/buck2/rust-toolchain + # And other similar references in this file and + # docusaurus.yml + toolchain: nightly-2024-10-13 override: true target: ${{ matrix.target.target }} - uses: actions/setup-node@v2 diff --git a/.github/workflows/docusaurus.yml b/.github/workflows/docusaurus.yml index 18feee2077769..4c3c2968eba1e 100644 --- a/.github/workflows/docusaurus.yml +++ b/.github/workflows/docusaurus.yml @@ -21,7 +21,10 @@ jobs: - uses: actions/checkout@v4 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.76.0 + # Should stay in sync with fbcode/buck2/rust-toolchain + # And other similar references in this file and + # ci.yml + toolchain: nightly-2024-10-13 override: true - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh diff --git a/.github/workflows/update-cargo-lock.yml b/.github/workflows/update-cargo-lock.yml index 92b35c81bbfa8..d358732ad1fcb 100644 --- a/.github/workflows/update-cargo-lock.yml +++ b/.github/workflows/update-cargo-lock.yml @@ -21,7 +21,10 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.76.0 + # Should stay in sync with fbcode/buck2/rust-toolchain + # And other similar references in this file and + # ci.yml + toolchain: nightly-2024-10-13 override: true - name: cargo check run: cargo check --features vendored --manifest-path=compiler/Cargo.toml diff --git a/compiler/Cargo.lock b/compiler/Cargo.lock index 3a614fa28e40d..8043e8603e02b 100644 --- a/compiler/Cargo.lock +++ b/compiler/Cargo.lock @@ -1,27 +1,27 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -46,15 +46,15 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -67,49 +67,50 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" [[package]] name = "assert_matches" @@ -119,13 +120,13 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -134,30 +135,30 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -183,9 +184,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "block-buffer" @@ -198,9 +199,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "serde", @@ -208,9 +209,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -220,31 +221,22 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - -[[package]] -name = "bytes" -version = "1.5.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] [[package]] name = "cc" -version = "1.0.83" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -261,9 +253,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.20" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -271,9 +263,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -286,36 +278,36 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -363,15 +355,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -391,18 +383,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -419,18 +411,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" @@ -449,7 +441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if 1.0.0", - "hashbrown", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -500,6 +492,17 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "docblock-shared" version = "0.0.0" @@ -522,15 +525,15 @@ dependencies = [ "graphql-test-helpers", "intern", "serde", - "thiserror", + "thiserror 2.0.11", "tokio", ] [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" @@ -540,9 +543,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "env_logger" @@ -565,21 +568,22 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d05712b2d8d88102bc9868020c9e5c7a1f5527c452b9b97450a1d006140ba7" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" dependencies = [ "serde", + "typeid", ] [[package]] name = "errno" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -602,9 +606,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fixedbitset" @@ -632,7 +636,7 @@ checksum = "86b428b715fdbdd1c364b84573b5fdc0f84f8e423661b9f398735278bc7f2b6a" dependencies = [ "bitflags 1.3.2", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -673,9 +677,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -688,9 +692,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -698,15 +702,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -715,38 +719,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures 0.1.31", "futures-channel", @@ -773,9 +777,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if 1.0.0", "libc", @@ -784,15 +788,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "globset" @@ -804,7 +808,7 @@ dependencies = [ "bstr", "log", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", "serde", ] @@ -834,7 +838,7 @@ dependencies = [ "schema", "serde", "strum", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -856,7 +860,7 @@ dependencies = [ "relay-test-schema", "schema", "serde", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -870,7 +874,7 @@ dependencies = [ "intern", "logos", "serde", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -917,11 +921,11 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ - "bytes 1.5.0", + "bytes", "fnv", "futures-core", "futures-sink", @@ -930,21 +934,27 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.10", + "tokio-util 0.7.13", "tracing", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "heck" version = "0.4.1" @@ -966,12 +976,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -980,11 +984,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ - "bytes 1.5.0", + "bytes", "fnv", "itoa", ] @@ -995,16 +999,16 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ - "bytes 1.5.0", + "bytes", "http", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1023,11 +1027,11 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ - "bytes 1.5.0", + "bytes", "futures-channel", "futures-core", "futures-util", @@ -1051,32 +1055,161 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.5.0", + "bytes", "hyper", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.2.6" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "arbitrary", "equivalent", - "hashbrown", + "hashbrown 0.15.2", "rayon", "serde", ] @@ -1087,7 +1220,7 @@ version = "0.1.0" dependencies = [ "bincode", "fnv", - "hashbrown", + "hashbrown 0.14.5", "indexmap", "once_cell", "parking_lot", @@ -1113,17 +1246,11 @@ dependencies = [ [[package]] name = "inventory" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" - -[[package]] -name = "iovec" -version = "0.1.4" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +checksum = "3b31349d02fe60f80bbbab1a9402364cad7460626d6030494b08ac4a2075bf81" dependencies = [ - "libc", + "rustversion", ] [[package]] @@ -1134,33 +1261,24 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.12.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -1172,41 +1290,51 @@ dependencies = [ "serde", "serde_json", "tempfile", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" -version = "0.2.153" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1214,9 +1342,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" dependencies = [ "value-bag", ] @@ -1246,13 +1374,14 @@ dependencies = [ [[package]] name = "lsp-server" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248f65b78f6db5d8e1b1604b4098a28b43d21a8eb1deeca22b1c421b276c7095" +checksum = "9462c4dc73e17f971ec1f171d44bfffb72e65a130117233388a0ebc7ec5656f9" dependencies = [ "crossbeam-channel", "log", "serde", + "serde_derive", "serde_json", ] @@ -1287,9 +1416,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memory_units" @@ -1297,22 +1426,31 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -1320,11 +1458,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -1353,26 +1490,26 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.63" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.8.0", "cfg-if 1.0.0", "foreign-types", "libc", @@ -1389,7 +1526,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -1400,18 +1537,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.2.2+3.2.1" +version = "300.4.1+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbfad0063610ac26ee79f7484739e2b07555a75c42453b89263830b5c8103bc" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.99" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -1422,9 +1559,9 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.18.4" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" dependencies = [ "aliasable", "ouroboros_macro", @@ -1433,23 +1570,22 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.18.4" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" dependencies = [ "heck 0.4.1", - "itertools 0.12.1", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1457,22 +1593,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -1488,15 +1624,15 @@ dependencies = [ "hyper-tls", "serde", "serde_json", - "thiserror", + "thiserror 2.0.11", "url", ] [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", @@ -1506,9 +1642,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1518,9 +1654,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "powerfmt" @@ -1530,15 +1666,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -1551,7 +1690,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", "version_check", "yansi", ] @@ -1564,9 +1703,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1623,34 +1762,34 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.8.0", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -1661,9 +1800,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relay" @@ -1679,7 +1818,7 @@ dependencies = [ "schema", "schema-documentation", "simplelog", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -1736,7 +1875,7 @@ dependencies = [ "extract-graphql", "fixture-tests", "fnv", - "futures 0.3.30", + "futures 0.3.31", "futures-util", "glob", "globset", @@ -1776,7 +1915,7 @@ dependencies = [ "sha1", "sha2", "signedsource", - "thiserror", + "thiserror 2.0.11", "tokio", "walkdir", "watchman_client", @@ -1845,7 +1984,7 @@ dependencies = [ "relay-test-schema", "schema", "serde", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -1869,7 +2008,7 @@ dependencies = [ "graphql-text-printer", "graphql-watchman", "intern", - "itertools 0.13.0", + "itertools", "lazy_static", "log", "lsp-server", @@ -1940,7 +2079,7 @@ dependencies = [ "graphql-text-printer", "indexmap", "intern", - "itertools 0.13.0", + "itertools", "lazy_static", "parking_lot", "regex", @@ -1950,7 +2089,7 @@ dependencies = [ "rustc-hash", "schema", "serde", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -1967,7 +2106,7 @@ dependencies = [ "graphql-test-helpers", "indexmap", "intern", - "itertools 0.13.0", + "itertools", "lazy_static", "log", "regex", @@ -1994,40 +2133,40 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2040,11 +2179,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2065,7 +2204,7 @@ dependencies = [ "schema-flatbuffer", "serde", "strsim 0.10.0", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -2106,7 +2245,7 @@ dependencies = [ "fixture-tests", "fnv", "intern", - "itertools 0.13.0", + "itertools", "rayon", "schema", "tokio", @@ -2127,7 +2266,7 @@ dependencies = [ "regex", "schema", "serde", - "thiserror", + "thiserror 2.0.11", "tokio", ] @@ -2153,15 +2292,9 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.48", + "syn 2.0.96", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -2170,11 +2303,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.8.0", "core-foundation", "core-foundation-sys", "libc", @@ -2183,9 +2316,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -2193,44 +2326,45 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_bser" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b929ea725591083cbca8b8ea178ed6efc918eccd40b784e199ce88967104199" +checksum = "a56b4bcc15e42e5b5ae16c6f75582bef80d36c6ffe2c03b1b5317754b38f8717" dependencies = [ "anyhow", "byteorder", - "bytes 0.4.12", + "bytes", "serde", - "thiserror", + "serde_bytes", + "thiserror 1.0.69", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -2241,7 +2375,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -2255,9 +2389,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -2267,13 +2401,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -2298,11 +2432,17 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -2339,23 +2479,35 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ "serde", ] [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -2376,37 +2528,37 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "sval" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6dc0f9830c49db20e73273ffae9b5240f63c42e515af1da1fceefb69fceafd8" +checksum = "7cc9739f56c5d0c44a5ed45473ec868af02eb896af8c05f616673a31e1d1bb09" [[package]] name = "sval_buffer" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "429922f7ad43c0ef8fd7309e14d750e38899e32eb7e8da656ea169dd28ee212f" +checksum = "f39b07436a8c271b34dad5070c634d1d3d76d6776e938ee97b4a66a5e8003d0b" dependencies = [ "sval", "sval_ref", @@ -2414,18 +2566,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f16ff5d839396c11a30019b659b0976348f3803db0626f736764c473b50ff4" +checksum = "ffcb072d857431bf885580dacecf05ed987bac931230736739a79051dbf3499b" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01c27a80b6151b0557f9ccbe89c11db571dc5f68113690c1e028d7e974bae94" +checksum = "3f214f427ad94a553e5ca5514c95c6be84667cbc5568cce957f03f3477d03d5c" dependencies = [ "itoa", "ryu", @@ -2434,9 +2586,9 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0deef63c70da622b2a8069d8600cf4b05396459e665862e7bdb290fd6cf3f155" +checksum = "389ed34b32e638dec9a99c8ac92d0aa1220d40041026b625474c2b6a4d6f4feb" dependencies = [ "itoa", "ryu", @@ -2445,9 +2597,9 @@ dependencies = [ [[package]] name = "sval_nested" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a39ce5976ae1feb814c35d290cf7cf8cd4f045782fe1548d6bc32e21f6156e9f" +checksum = "14bae8fcb2f24fee2c42c1f19037707f7c9a29a0cda936d2188d48a961c4bb2a" dependencies = [ "sval", "sval_buffer", @@ -2456,18 +2608,18 @@ dependencies = [ [[package]] name = "sval_ref" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7c6ee3751795a728bc9316a092023529ffea1783499afbc5c66f5fabebb1fa" +checksum = "2a4eaea3821d3046dcba81d4b8489421da42961889902342691fb7eab491d79e" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5572d0321b68109a343634e3a5d576bf131b82180c6c442dee06349dfc652a" +checksum = "172dd4aa8cb3b45c8ac8f3b4111d644cd26938b0643ede8f93070812b87fb339" dependencies = [ "serde", "sval", @@ -2487,41 +2639,54 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "tempfile" -version = "3.10.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if 1.0.0", "fastrand", + "getrandom", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -2529,29 +2694,49 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -2572,37 +2757,32 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.41.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", - "bytes 1.5.0", + "bytes", "libc", "mio", "parking_lot", @@ -2616,13 +2796,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -2641,7 +2821,7 @@ version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ - "bytes 1.5.0", + "bytes", "futures-core", "futures-io", "futures-sink", @@ -2653,29 +2833,28 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ - "bytes 1.5.0", + "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -2683,9 +2862,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] @@ -2696,6 +2875,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + [[package]] name = "typenum" version = "1.17.0" @@ -2704,9 +2889,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typetag" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43148481c7b66502c48f35b8eef38b6ccdc7a9f04bd4cc294226d901ccc9bc7" +checksum = "044fc3365ddd307c297fe0fe7b2e70588cdab4d0f62dc52055ca0d11b174cf0e" dependencies = [ "erased-serde", "inventory", @@ -2717,44 +2902,26 @@ dependencies = [ [[package]] name = "typetag-impl" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291db8a81af4840c10d636e047cac67664e343be44e24dfdbd1492df9a5d3390" +checksum = "d9d30226ac9cbd2d1ff775f74e8febdab985dab14fb14aa2582c29a92d5555dc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" @@ -2764,9 +2931,9 @@ checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -2774,6 +2941,18 @@ dependencies = [ "serde", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -2782,9 +2961,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "value-bag" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126e423afe2dd9ac52142e7e9d5ce4135d7e13776c529d27fd6bc49f19e3280b" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -2792,9 +2971,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b" +checksum = "35540706617d373b118d550d41f5dfe0b78a0c195dc13c6815e92e2638432306" dependencies = [ "erased-serde", "serde", @@ -2803,9 +2982,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a" +checksum = "6fe7e140a2658cc16f7ee7a86e413e803fc8f9b5127adc8755c19f9fefa63a52" dependencies = [ "sval", "sval_buffer", @@ -2824,15 +3003,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2855,46 +3034,48 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if 1.0.0", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.41" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if 1.0.0", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2902,32 +3083,34 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-bindgen-test" -version = "0.3.41" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143ddeb4f833e2ed0d252e618986e18bfc7b0e52f2d28d77d05b2f045dd8eb61" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" dependencies = [ - "console_error_panic_hook", "js-sys", - "scoped-tls", + "minicov", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", @@ -2935,28 +3118,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.41" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5211b7550606857312bba1d978a8ec75692eae187becc5e680444fffc5e6f89" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "watchman_client" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "839fea2d85719bb69089290d7970bba2131f544448db8f990ea75813c30775ca" +checksum = "88bc4c9bb443a7aae10d4fa7807bffc397805315e2305288c90c80e2f66cfb52" dependencies = [ "anyhow", - "bytes 1.5.0", - "futures 0.3.30", + "bytes", + "futures 0.3.31", "maplit", "serde", "serde_bser", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-util 0.6.10", "winapi", @@ -2964,9 +3147,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.68" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -3002,11 +3185,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -3015,22 +3198,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3039,22 +3213,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -3063,46 +3222,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3115,24 +3256,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -3141,27 +3270,27 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "windows_x86_64_gnullvm" +name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +name = "write16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "writeable" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "yansi" @@ -3169,49 +3298,117 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "synstructure", +] + [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] name = "zstd" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.0.0" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/compiler/crates/common/Cargo.toml b/compiler/crates/common/Cargo.toml index df6d4848f7100..d710c7821328c 100644 --- a/compiler/crates/common/Cargo.toml +++ b/compiler/crates/common/Cargo.toml @@ -18,5 +18,5 @@ md-5 = "0.10" rayon = "1.9.0" schemars = { version = "0.8.21", features = ["indexmap2"] } serde = { version = "1.0.185", features = ["derive", "rc"] } -serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } +serde_json = { version = "1.0.140", features = ["float_roundtrip", "unbounded_depth"] } typetag = "0.2.15" diff --git a/compiler/crates/common/src/feature_flags.rs b/compiler/crates/common/src/feature_flags.rs index 8e3943e4c5022..2037d8702b83f 100644 --- a/compiler/crates/common/src/feature_flags.rs +++ b/compiler/crates/common/src/feature_flags.rs @@ -16,6 +16,7 @@ use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; +use crate::rollout::RolloutRange; use crate::Rollout; #[derive(Default, Debug, Serialize, Deserialize, Clone, JsonSchema)] @@ -49,7 +50,7 @@ pub struct FeatureFlags { /// Enforce that you must add `@alias` to a fragment if it may not match, /// due to type mismatch or `@skip`/`@include` - #[serde(default)] + #[serde(default = "enabled_feature_flag")] pub enforce_fragment_alias_where_ambiguous: FeatureFlag, /// Print queries in compact form @@ -183,6 +184,14 @@ pub enum FeatureFlag { /// Partially enabled: used for gradual rollout of the feature Rollout { rollout: Rollout }, + + /// Partially enabled: used for gradual rollout of the feature + RolloutRange { rollout: RolloutRange }, +} + +/// Used for making feature flags enabled by default via Serde's default attribute. +fn enabled_feature_flag() -> FeatureFlag { + FeatureFlag::Enabled } impl FeatureFlag { @@ -191,6 +200,7 @@ impl FeatureFlag { FeatureFlag::Enabled => true, FeatureFlag::Limited { allowlist } => allowlist.contains(&name), FeatureFlag::Rollout { rollout } => rollout.check(name.lookup()), + FeatureFlag::RolloutRange { rollout } => rollout.check(name.lookup()), FeatureFlag::Disabled => false, } } @@ -211,6 +221,7 @@ impl Display for FeatureFlag { f.write_str(&items.join(", ")) } FeatureFlag::Rollout { rollout } => write!(f, "Rollout: {:#?}", rollout), + FeatureFlag::RolloutRange { rollout } => write!(f, "RolloutRange: {:#?}", rollout), } } } diff --git a/compiler/crates/common/src/lib.rs b/compiler/crates/common/src/lib.rs index b2f4b8b066a8f..5e52cb88ee8d8 100644 --- a/compiler/crates/common/src/lib.rs +++ b/compiler/crates/common/src/lib.rs @@ -8,7 +8,9 @@ #![deny(warnings)] #![deny(rust_2018_idioms)] #![deny(clippy::all)] - +// This warning is triggered by code generated by derive macro typetag-impl-0.2.15 +// Supressing for now to get Relay building +#![allow(non_local_definitions)] mod console_logger; mod diagnostic; mod diagnostic_check; @@ -62,5 +64,6 @@ pub use perf_logger::PerfLogEvent; pub use perf_logger::PerfLogger; pub use pointer_address::PointerAddress; pub use rollout::Rollout; +pub use rollout::RolloutRange; pub use span::Span; pub use text_source::TextSource; diff --git a/compiler/crates/common/src/rollout.rs b/compiler/crates/common/src/rollout.rs index 92afe103cd1da..f69c4d8fb1903 100644 --- a/compiler/crates/common/src/rollout.rs +++ b/compiler/crates/common/src/rollout.rs @@ -31,3 +31,23 @@ impl Rollout { } } } + +/// A utility to enable gradual rollout of large codegen changes. Allows you to +/// specify a range of percentages to rollout. +#[derive(Debug, Serialize, Deserialize, Clone, Copy, JsonSchema)] +pub struct RolloutRange { + pub start: u8, + pub end: u8, +} + +impl RolloutRange { + /// Checks some key deterministically and passes on average the given + /// percentage of the rollout. + /// A typical key to pass in could be the fragment or operation name. + pub fn check(&self, key: impl AsRef<[u8]>) -> bool { + let hash = Md5::digest(key.as_ref()); + let hash: u16 = ((hash[1] as u16) << 8) | (hash[0] as u16); + let percent = hash % 100; + (percent) <= (self.end as u16) && (percent) >= (self.start as u16) + } +} diff --git a/compiler/crates/dependency-analyzer/Cargo.toml b/compiler/crates/dependency-analyzer/Cargo.toml index aabc37ba9337a..9c78ee535cb11 100644 --- a/compiler/crates/dependency-analyzer/Cargo.toml +++ b/compiler/crates/dependency-analyzer/Cargo.toml @@ -21,7 +21,7 @@ common = { path = "../common" } graphql-ir = { path = "../graphql-ir" } graphql-syntax = { path = "../graphql-syntax" } relay-transforms = { path = "../relay-transforms" } -rustc-hash = "1.1.0" +rustc-hash = "2.1.0" schema = { path = "../schema" } schema-diff = { path = "../schema-diff" } serde = { version = "1.0.185", features = ["derive", "rc"] } diff --git a/compiler/crates/docblock-shared/Cargo.toml b/compiler/crates/docblock-shared/Cargo.toml index 6b28e5837e2d3..85d3a2eb28e41 100644 --- a/compiler/crates/docblock-shared/Cargo.toml +++ b/compiler/crates/docblock-shared/Cargo.toml @@ -10,8 +10,8 @@ license = "MIT" [dependencies] common = { path = "../common" } -hex = "0.4.3" +hex = { version = "0.4.3", features = ["alloc"] } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } md-5 = "0.10" serde = { version = "1.0.185", features = ["derive", "rc"] } diff --git a/compiler/crates/docblock-shared/src/lib.rs b/compiler/crates/docblock-shared/src/lib.rs index 931b9677965f7..7652c5119a362 100644 --- a/compiler/crates/docblock-shared/src/lib.rs +++ b/compiler/crates/docblock-shared/src/lib.rs @@ -38,6 +38,9 @@ lazy_static! { /// a Relay Resolver model. pub static ref RELAY_RESOLVER_MODEL_DIRECTIVE_NAME: DirectiveName = DirectiveName("__RelayResolverModel".intern()); + /// A field directive which indicates that the field is the generated ID field for a model type. + pub static ref RELAY_RESOLVER_MODEL_GENERATED_ID_FIELD_DIRECTIVE_NAME: DirectiveName = + DirectiveName("__RelayResolverModelGeneratedIDField".intern()); /// If a field or model type has a @relay_resolver directive (see above) /// this argument name is used to track its @rootFragment (if any). pub static ref FRAGMENT_KEY_ARGUMENT_NAME: ArgumentName = @@ -46,6 +49,10 @@ lazy_static! { /// has validated that its Flow/TypeScript type matches the GraphQL type. pub static ref TYPE_CONFIRMED_ARGUMENT_NAME: ArgumentName = ArgumentName("type_confirmed".intern()); + /// Indicates that the resolver is just a property lookup on the underlying model (and we need to generate + /// code to do this lookup) + pub static ref RESOLVER_PROPERTY_LOOKUP_NAME: ArgumentName = + ArgumentName("property_lookup_name".intern()); /// "Weak" resolver types are types which are backed by a JS model value, but which don't have a stable /// identity. Types in the generated schema are annotated with a directive using this name to signal /// to the rest of Relay that they are backed by a "weak" Relay Resolver model. diff --git a/compiler/crates/docblock-syntax/Cargo.toml b/compiler/crates/docblock-syntax/Cargo.toml index 7882c978138f2..95c186e341270 100644 --- a/compiler/crates/docblock-syntax/Cargo.toml +++ b/compiler/crates/docblock-syntax/Cargo.toml @@ -17,7 +17,7 @@ common = { path = "../common" } docblock-shared = { path = "../docblock-shared" } intern = { path = "../intern" } serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] fixture-tests = { path = "../fixture-tests" } diff --git a/compiler/crates/docblock-syntax/src/lib.rs b/compiler/crates/docblock-syntax/src/lib.rs index 146209356c6c8..ecc6496b83bba 100644 --- a/compiler/crates/docblock-syntax/src/lib.rs +++ b/compiler/crates/docblock-syntax/src/lib.rs @@ -238,7 +238,11 @@ impl<'a> DocblockParser<'a> { /// Read until the end of the line. fn parse_free_text_line(&mut self) -> ParseResult { let start = self.offset; - let free_text = self.take_while(|c| c != &'\n'); + let mut free_text: String = self.take_while(|c| c != &'\n'); + // Handle CRLF by stripping `\r` suffix. + if free_text.ends_with('\r') { + free_text.pop(); + } let end = self.offset; Ok(SpanString::new(Span::new(start, end), free_text)) } diff --git a/compiler/crates/errors/src/error_combinators.rs b/compiler/crates/errors/src/error_combinators.rs index f13a1f7163531..50a2fcbbfc851 100644 --- a/compiler/crates/errors/src/error_combinators.rs +++ b/compiler/crates/errors/src/error_combinators.rs @@ -132,14 +132,16 @@ where } /// Similar to `try_map` but performs the transform in parallel. -pub fn par_try_map( +pub fn par_try_map< + T: Sync + Send, + E: Sync + Send, + U: Sync + Send, + I: IntoParallelIterator + IntoIterator, + F: Sync + Send + Fn(U) -> Result>, +>( items: I, f: F, -) -> Result, Vec> -where - I: IntoParallelIterator + IntoIterator, - F: Fn(U) -> Result>, -{ +) -> Result, Vec> { let results: Vec>> = par_iter(items).map(f).collect(); let mut errors = Vec::new(); let mut values = Vec::with_capacity(results.len()); diff --git a/compiler/crates/extract-graphql/src/lib.rs b/compiler/crates/extract-graphql/src/lib.rs index 32f039fa9db82..00c1d84d95eeb 100644 --- a/compiler/crates/extract-graphql/src/lib.rs +++ b/compiler/crates/extract-graphql/src/lib.rs @@ -57,7 +57,7 @@ impl<'a> CharReader<'a> { } } -impl<'a> Iterator for CharReader<'a> { +impl Iterator for CharReader<'_> { type Item = (usize, char); fn next(&mut self) -> Option { let pair = self.chars.next(); diff --git a/compiler/crates/fixture-tests/Cargo.toml b/compiler/crates/fixture-tests/Cargo.toml index 75b4e3a539010..b9a7fda71b9d2 100644 --- a/compiler/crates/fixture-tests/Cargo.toml +++ b/compiler/crates/fixture-tests/Cargo.toml @@ -17,9 +17,9 @@ name = "fixture_tests_tests" path = "tests/uppercase_test.rs" [dependencies] -clap = { version = "4.5.20", features = ["derive", "env", "string", "unicode", "wrap_help"] } +clap = { version = "4.5.30", features = ["derive", "env", "string", "unicode", "wrap_help"] } colored = "2.1.0" diff = "0.1" -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } signedsource = { path = "../signedsource" } tokio = { version = "1.41.0", features = ["full", "test-util", "tracing"] } diff --git a/compiler/crates/graphql-ir-validations/Cargo.toml b/compiler/crates/graphql-ir-validations/Cargo.toml index 293c255af43a6..f56914e36b4ff 100644 --- a/compiler/crates/graphql-ir-validations/Cargo.toml +++ b/compiler/crates/graphql-ir-validations/Cargo.toml @@ -22,7 +22,7 @@ intern = { path = "../intern" } relay-config = { path = "../relay-config" } schema = { path = "../schema" } serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] fixture-tests = { path = "../fixture-tests" } diff --git a/compiler/crates/graphql-ir/Cargo.toml b/compiler/crates/graphql-ir/Cargo.toml index 35e01f54a70c8..012821d05915d 100644 --- a/compiler/crates/graphql-ir/Cargo.toml +++ b/compiler/crates/graphql-ir/Cargo.toml @@ -27,12 +27,12 @@ fnv = "1.0" graphql-syntax = { path = "../graphql-syntax" } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } once_cell = "1.12" schema = { path = "../schema" } serde = { version = "1.0.185", features = ["derive", "rc"] } strum = { version = "0.26.2", features = ["derive"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] fixture-tests = { path = "../fixture-tests" } diff --git a/compiler/crates/graphql-ir/src/errors.rs b/compiler/crates/graphql-ir/src/errors.rs index 9d6527031c7fc..7399517b384de 100644 --- a/compiler/crates/graphql-ir/src/errors.rs +++ b/compiler/crates/graphql-ir/src/errors.rs @@ -18,13 +18,17 @@ use intern::Lookup; use schema::suggestion_list::did_you_mean; use schema::Type; use schema::TypeReference; +use serde::Deserialize; use thiserror::Error; use crate::ir::FragmentDefinitionName; use crate::VariableName; #[derive( + Debug, + Deserialize, Eq, + Hash, Ord, PartialEq, PartialOrd, diff --git a/compiler/crates/graphql-ir/src/ir.rs b/compiler/crates/graphql-ir/src/ir.rs index 7ab3e58a5bd4e..2c450e201c05b 100644 --- a/compiler/crates/graphql-ir/src/ir.rs +++ b/compiler/crates/graphql-ir/src/ir.rs @@ -11,6 +11,7 @@ use std::fmt; use std::fmt::Display; use std::fmt::Formatter; use std::hash::Hash; +use std::hash::Hasher; use std::str::FromStr; use std::sync::Arc; @@ -151,7 +152,9 @@ pub type FragmentDefinitionNameSet = HashSet, + /// Local variables defined in the fragment using the `@argumentDefinitions` directive. pub variable_definitions: Vec, + /// Global variables that are used but NOT defined within the fragment (they can come from a parent query or fragment). pub used_global_variables: Vec, pub type_condition: Type, pub directives: Vec, @@ -297,7 +300,7 @@ impl Named for VariableDefinition { // Selections /// A selection within an operation or fragment -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, Hash)] pub enum Selection { FragmentSpread(Arc), InlineFragment(Arc), @@ -402,7 +405,7 @@ impl fmt::Debug for Selection { } /// ... Name -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct FragmentSpread { pub fragment: WithLocation, pub arguments: Vec, @@ -438,6 +441,16 @@ pub struct InlineFragment { pub spread_location: Location, } +impl Hash for InlineFragment { + fn hash(&self, state: &mut H) { + self.type_condition.hash(state); + self.directives.hash(state); + self.spread_location.hash(state); + // Avoid descending into selections, which leads to large recursion + self.selections.len().hash(state); + } +} + impl InlineFragment { /// Get the alias of this inline fragment from the optional `@alias` directive. /// If the `as` argument is not present, the type condition is used as the fallback. @@ -496,6 +509,17 @@ pub struct LinkedField { pub selections: Vec, } +impl Hash for LinkedField { + fn hash(&self, state: &mut H) { + self.alias.hash(state); + self.definition.hash(state); + self.arguments.hash(state); + self.directives.hash(state); + // Avoid descending into selections, which leads to large recursion + self.selections.len().hash(state); + } +} + impl Field for LinkedField { fn alias(&self) -> Option> { self.alias @@ -515,7 +539,7 @@ impl Field for LinkedField { } /// Name Arguments? -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct ScalarField { pub alias: Option>, pub definition: WithLocation, @@ -550,6 +574,16 @@ pub struct Condition { pub location: Location, } +impl Hash for Condition { + fn hash(&self, state: &mut H) { + self.value.hash(state); + self.passing_value.hash(state); + self.location.hash(state); + // Avoid descending into selections, which leads to large recursion + self.selections.len().hash(state); + } +} + impl Condition { pub fn directive_name(&self) -> &'static str { if self.passing_value { @@ -634,6 +668,14 @@ impl Value { panic!("expected a string literal, got {:?}", self); }) } + + pub fn expect_list(&self) -> Option> { + if let Value::List(list) = self { + Some(list.clone()) + } else { + None + } + } } #[derive(Clone, Debug, Eq, PartialEq, Hash)] @@ -703,7 +745,7 @@ impl ConstantValue { generate_unwrap_fn!(unwrap_object, self, &Vec, ConstantValue::Object(o) => o); } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum ConditionValue { Constant(bool), Variable(Variable), diff --git a/compiler/crates/graphql-ir/src/lib.rs b/compiler/crates/graphql-ir/src/lib.rs index b17a3c956e34c..34aaa23176afc 100644 --- a/compiler/crates/graphql-ir/src/lib.rs +++ b/compiler/crates/graphql-ir/src/lib.rs @@ -35,7 +35,9 @@ pub use build::FIXME_FAT_INTERFACE; pub use constants::ARGUMENT_DEFINITION; pub use ir::*; pub use program::Program; +pub use signatures::build_signatures; pub use signatures::FragmentSignature; +pub use signatures::FragmentSignatures; pub use signatures::ProvidedVariableMetadata; pub use signatures::UNUSED_LOCAL_VARIABLE_DEPRECATED; pub use transform::transform_list; diff --git a/compiler/crates/graphql-ir/src/signatures.rs b/compiler/crates/graphql-ir/src/signatures.rs index e04cddd274aa2..64f3023141eec 100644 --- a/compiler/crates/graphql-ir/src/signatures.rs +++ b/compiler/crates/graphql-ir/src/signatures.rs @@ -35,9 +35,11 @@ use crate::build::build_variable_definitions; use crate::build::ValidationLevel; use crate::build_directive; use crate::constants::ARGUMENT_DEFINITION; +use crate::errors::MachineMetadataKey; use crate::errors::ValidationMessage; use crate::errors::ValidationMessageWithData; use crate::ir::ConstantValue; +use crate::ir::FragmentDefinition; use crate::ir::FragmentDefinitionName; use crate::ir::FragmentDefinitionNameMap; use crate::ir::VariableDefinition; @@ -82,7 +84,7 @@ associated_data_impl!(ProvidedVariableMetadata); /// would depend on having checked its body! Since recursive fragments /// are allowed, we break the cycle by first computing signatures /// and using these to type check fragment spreads in selections. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct FragmentSignature { pub name: WithLocation, pub variable_definitions: Vec, @@ -90,6 +92,17 @@ pub struct FragmentSignature { pub directives: Vec, } +impl From<&FragmentDefinition> for FragmentSignature { + fn from(fragment: &FragmentDefinition) -> Self { + Self { + name: fragment.name, + variable_definitions: fragment.variable_definitions.clone(), + type_condition: fragment.type_condition, + directives: fragment.directives.clone(), + } + } +} + pub fn build_signatures( schema: &SDLSchema, definitions: &[graphql_syntax::ExecutableDefinition], @@ -151,7 +164,7 @@ fn build_fragment_signature( .location .with_span(fragment.type_condition.type_.span), ) - .metadata_for_machine("unknown_type", type_name.lookup()) + .metadata_for_machine(MachineMetadataKey::UnknownType, type_name.lookup()) .into()), }; let argument_definition_directives = fragment diff --git a/compiler/crates/graphql-ir/src/transform.rs b/compiler/crates/graphql-ir/src/transform.rs index ce48df44e4e4b..5cfd41099e387 100644 --- a/compiler/crates/graphql-ir/src/transform.rs +++ b/compiler/crates/graphql-ir/src/transform.rs @@ -12,17 +12,17 @@ use common::WithLocation; use crate::ir::*; use crate::program::Program; -pub trait Transformer { +pub trait Transformer<'a> { const NAME: &'static str; const VISIT_ARGUMENTS: bool; const VISIT_DIRECTIVES: bool; const RETAIN_EMPTY_SELECTION_SETS: bool = false; - fn transform_program(&mut self, program: &Program) -> TransformedValue { + fn transform_program(&mut self, program: &'a Program) -> TransformedValue { self.default_transform_program(program) } - fn default_transform_program(&mut self, program: &Program) -> TransformedValue { + fn default_transform_program(&mut self, program: &'a Program) -> TransformedValue { let mut next_program = Program::new(Arc::clone(&program.schema)); let mut has_changes = false; for operation in program.operations() { @@ -55,14 +55,14 @@ pub trait Transformer { // Fragment Definition fn transform_fragment( &mut self, - fragment: &FragmentDefinition, + fragment: &'a FragmentDefinition, ) -> Transformed { self.default_transform_fragment(fragment) } fn default_transform_fragment( &mut self, - fragment: &FragmentDefinition, + fragment: &'a FragmentDefinition, ) -> Transformed { let selections = self.transform_selections(&fragment.selections); let directives = self.transform_directives(&fragment.directives); @@ -95,14 +95,14 @@ pub trait Transformer { // Operation Definition fn transform_operation( &mut self, - operation: &OperationDefinition, + operation: &'a OperationDefinition, ) -> Transformed { self.default_transform_operation(operation) } fn default_transform_operation( &mut self, - operation: &OperationDefinition, + operation: &'a OperationDefinition, ) -> Transformed { let selections = self.transform_selections(&operation.selections); let directives = self.transform_directives(&operation.directives); @@ -172,16 +172,16 @@ pub trait Transformer { // Selection fn transform_selections( &mut self, - selections: &[Selection], + selections: &'a [Selection], ) -> TransformedValue> { transform_list(selections, |selection| self.transform_selection(selection)) } - fn transform_selection(&mut self, selection: &Selection) -> Transformed { + fn transform_selection(&mut self, selection: &'a Selection) -> Transformed { self.default_transform_selection(selection) } - fn default_transform_selection(&mut self, selection: &Selection) -> Transformed { + fn default_transform_selection(&mut self, selection: &'a Selection) -> Transformed { match selection { Selection::FragmentSpread(selection) => self.transform_fragment_spread(selection), Selection::InlineFragment(selection) => self.transform_inline_fragment(selection), @@ -209,11 +209,11 @@ pub trait Transformer { }))) } - fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed { + fn transform_linked_field(&mut self, field: &'a LinkedField) -> Transformed { self.default_transform_linked_field(field) } - fn default_transform_linked_field(&mut self, field: &LinkedField) -> Transformed { + fn default_transform_linked_field(&mut self, field: &'a LinkedField) -> Transformed { // Special-case for empty selections let selections = self.transform_selections(&field.selections); if let TransformedValue::Replace(selections) = &selections { @@ -234,13 +234,16 @@ pub trait Transformer { }))) } - fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed { + fn transform_inline_fragment( + &mut self, + fragment: &'a InlineFragment, + ) -> Transformed { self.default_transform_inline_fragment(fragment) } fn default_transform_inline_fragment( &mut self, - fragment: &InlineFragment, + fragment: &'a InlineFragment, ) -> Transformed { // Special-case for empty selections let selections = self.transform_selections(&fragment.selections); @@ -280,11 +283,11 @@ pub trait Transformer { } // Conditions - fn transform_condition(&mut self, condition: &Condition) -> Transformed { + fn transform_condition(&mut self, condition: &'a Condition) -> Transformed { self.default_transform_condition(condition) } - fn default_transform_condition(&mut self, condition: &Condition) -> Transformed { + fn default_transform_condition(&mut self, condition: &'a Condition) -> Transformed { // Special-case for empty selections let selections = self.transform_selections(&condition.selections); if let TransformedValue::Replace(selections) = &selections { @@ -399,10 +402,10 @@ pub trait Transformer { } // Helpers -pub fn transform_list(list: &[T], mut transform: F) -> TransformedValue> +pub fn transform_list<'a, T, F, R>(list: &'a [T], mut transform: F) -> TransformedValue> where T: Clone, - F: FnMut(&T) -> R, + F: FnMut(&'a T) -> R, R: Into>, { let mut result = Vec::new(); @@ -519,7 +522,7 @@ impl TransformProgramPipe { pub fn pipe(self, transformer: T) -> Self where - T: Transformer, + T: for<'a> Transformer<'a>, { let mut transformer = transformer; let initial = self.initial; @@ -539,7 +542,7 @@ impl TransformProgramPipe { pub fn pipe_option(self, option: Option, get_transformer: F) -> Self where - T: Transformer, + T: for<'a> Transformer<'a>, F: FnOnce(X) -> T, { if let Some(x) = option { diff --git a/compiler/crates/graphql-syntax/Cargo.toml b/compiler/crates/graphql-syntax/Cargo.toml index 45c63da19dbee..82218b1dbb5a4 100644 --- a/compiler/crates/graphql-syntax/Cargo.toml +++ b/compiler/crates/graphql-syntax/Cargo.toml @@ -17,7 +17,7 @@ common = { path = "../common" } intern = { path = "../intern" } logos = "0.12" serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] fixture-tests = { path = "../fixture-tests" } diff --git a/compiler/crates/graphql-syntax/src/lib.rs b/compiler/crates/graphql-syntax/src/lib.rs index 8b37cc4868b29..7e523f2ec09a8 100644 --- a/compiler/crates/graphql-syntax/src/lib.rs +++ b/compiler/crates/graphql-syntax/src/lib.rs @@ -105,10 +105,10 @@ pub fn parse_schema_document( /// Parses a GraphQL schema document into a list of slices of the original /// source text where each slice is a type system definition. -pub fn parse_schema_document_into_type_system_definitions<'a>( - source: &'a str, +pub fn parse_schema_document_into_type_system_definitions( + source: &str, source_location: SourceLocationKey, -) -> DiagnosticsResult> { +) -> DiagnosticsResult> { let features = ParserFeatures::default(); let parser = Parser::new(source, source_location, features); parser.parse_schema_document_into_type_system_definitions() diff --git a/compiler/crates/graphql-syntax/src/parser.rs b/compiler/crates/graphql-syntax/src/parser.rs index 0789b371f1276..03e9d401e4ba4 100644 --- a/compiler/crates/graphql-syntax/src/parser.rs +++ b/compiler/crates/graphql-syntax/src/parser.rs @@ -1792,7 +1792,6 @@ impl<'a> Parser<'a> { match token.kind { TokenKind::Identifier => { self.advance_identifier()?; - () } TokenKind::OpenBracket => { self.advance_kind(TokenKind::OpenBracket)?; // open diff --git a/compiler/crates/graphql-text-printer/src/print_full_operation.rs b/compiler/crates/graphql-text-printer/src/print_full_operation.rs index c9f059503e55c..88675bbc41cc5 100644 --- a/compiler/crates/graphql-text-printer/src/print_full_operation.rs +++ b/compiler/crates/graphql-text-printer/src/print_full_operation.rs @@ -72,7 +72,7 @@ impl<'s> OperationPrinter<'s> { } } -impl<'s> Visitor for OperationPrinter<'s> { +impl Visitor for OperationPrinter<'_> { const NAME: &'static str = "OperationPrinter"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/graphql-watchman/Cargo.toml b/compiler/crates/graphql-watchman/Cargo.toml index 2ecda44a9ab62..a1c7bf92edb3d 100644 --- a/compiler/crates/graphql-watchman/Cargo.toml +++ b/compiler/crates/graphql-watchman/Cargo.toml @@ -11,5 +11,5 @@ license = "MIT" [dependencies] log = { version = "0.4.22", features = ["kv_unstable"] } serde = { version = "1.0.185", features = ["derive", "rc"] } -serde_bser = "0.3" -watchman_client = "0.8.0" +serde_bser = "0.4" +watchman_client = "0.9.0" diff --git a/compiler/crates/intern/Cargo.toml b/compiler/crates/intern/Cargo.toml index 2a2a3edb5b91a..9d4d4d87f02ab 100644 --- a/compiler/crates/intern/Cargo.toml +++ b/compiler/crates/intern/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" [dependencies] fnv = "1.0" -hashbrown = { version = "0.14.3", features = ["raw", "serde"] } +hashbrown = { version = "0.14.5", features = ["raw", "serde"] } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } once_cell = "1.12" parking_lot = { version = "0.12.1", features = ["send_guard"] } @@ -19,9 +19,12 @@ schemars = { version = "0.8.21", features = ["indexmap2"] } serde = { version = "1.0.185", features = ["derive", "rc"] } serde_bytes = "0.11" serde_derive = "1.0.185" -smallvec = { version = "1.6.1", features = ["serde", "union"] } +smallvec = { version = "1.13.2", features = ["serde", "union"] } [dev-dependencies] bincode = "1.3.3" rand = { version = "0.8", features = ["small_rng"] } -serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } +serde_json = { version = "1.0.140", features = ["float_roundtrip", "unbounded_depth"] } + +[lints] +rust = { unexpected_cfgs = { check-cfg = ["cfg(memory_consistency_assertions)"], level = "warn" } } diff --git a/compiler/crates/intern/src/atomic_arena.rs b/compiler/crates/intern/src/atomic_arena.rs index 55f5b9f69c1fa..00bdfefd0f5fe 100644 --- a/compiler/crates/intern/src/atomic_arena.rs +++ b/compiler/crates/intern/src/atomic_arena.rs @@ -25,7 +25,7 @@ const MIN_SHIFT: u32 = 7; const U32_BITS: usize = 32; const MIN_SIZE: u32 = 1 << MIN_SHIFT; const NUM_SIZES: usize = U32_BITS - MIN_SHIFT as usize; -const MAX_INDEX: u32 = std::u32::MAX - MIN_SIZE; +const MAX_INDEX: u32 = u32::MAX - MIN_SIZE; // Memory consistency assertions provide a lot of checking of the internals, // but have a huge runtime cost. Be warned! These are really for active @@ -207,7 +207,7 @@ fn bucket_capacity(a: usize) -> usize { fn index(i: u32) -> (usize, usize) { memory_consistency_assert!(i >= MIN_SIZE); memory_consistency_assert!(i - MIN_SIZE <= MAX_INDEX); - memory_consistency_assert!(i as u64 <= std::usize::MAX as u64); + memory_consistency_assert!(i as u64 <= usize::MAX as u64); let a = i.leading_zeros() as usize; memory_consistency_assert!(a < NUM_SIZES, "{} < {}", a, NUM_SIZES); let b = (i & ((bucket_capacity(0) as u32 - 1) >> a)) as usize; @@ -703,7 +703,7 @@ mod tests { let (a, b) = index(MIN_SIZE); assert_eq!(a, NUM_SIZES - 1); assert_eq!(b, 0); - let (a, b) = index(std::u32::MAX); + let (a, b) = index(u32::MAX); assert_eq!(a, 0); assert_eq!(b, (1 << 31) - 1); assert_eq!(b, bucket_capacity(0) - 1); diff --git a/compiler/crates/intern/src/intern.rs b/compiler/crates/intern/src/intern.rs index d11e3847f61ec..4efd26ebdb278 100644 --- a/compiler/crates/intern/src/intern.rs +++ b/compiler/crates/intern/src/intern.rs @@ -15,7 +15,6 @@ use std::hash::Hasher; use std::num::NonZeroU32; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; -use std::u32; use once_cell::sync::OnceCell; use serde::Deserialize; @@ -242,7 +241,7 @@ impl InternTable { impl InternTable { /// The methods from here on are internal and private. - fn shards(&'static self) -> &Shards { + fn shards(&'static self) -> &'static Shards { self.shards.get_or_init(|| { let shards: Shards = ShardedSet::default(); if !self.arena.is_empty() { @@ -291,7 +290,7 @@ impl InternTable { /// Get a shared reference to the underlying `Id::Intern`. /// Usually you can rely on `deref` to do this implicitly. #[inline] - fn get(&'static self, r: Id) -> &Id::Intern { + fn get(&'static self, r: Id) -> &'static Id::Intern { self.arena.get(r.unwrap()) } @@ -736,7 +735,7 @@ mod tests { impl std::cmp::PartialOrd for MyId { fn partial_cmp(&self, other: &Self) -> std::option::Option { - self.get().partial_cmp(other.get()) + Some(self.get().cmp(other.get())) } } diff --git a/compiler/crates/intern/src/sharded_set.rs b/compiler/crates/intern/src/sharded_set.rs index d2673ed0c4d6e..5367f072c723c 100644 --- a/compiler/crates/intern/src/sharded_set.rs +++ b/compiler/crates/intern/src/sharded_set.rs @@ -11,7 +11,7 @@ use std::fmt; use std::hash::BuildHasher; use std::hash::Hash; -use hashbrown::raw::RawTable; +use hashbrown::HashTable; use parking_lot::RwLock; use parking_lot::RwLockWriteGuard; @@ -20,7 +20,7 @@ const SHARDS: usize = 1 << SHARD_SHIFT; pub struct ShardedSet { build_hasher: S, - shards: [RwLock>; SHARDS], + shards: [RwLock>; SHARDS], } impl fmt::Debug for ShardedSet { @@ -308,7 +308,7 @@ fn hash_one(build_hasher: &B, x: T) -> u64 { pub struct InsertLock<'a, T, S = RandomState> { build_hasher: &'a S, hash: u64, - shard: RwLockWriteGuard<'a, RawTable>, + shard: RwLockWriteGuard<'a, HashTable>, } impl<'a, T, S> fmt::Debug for InsertLock<'a, T, S> { @@ -322,7 +322,7 @@ impl ShardedSet { /// hashbrown uses the upper 7 bits for disambiguation and the lower bits /// for bucket indexing, we take the bits just above the top 7. #[inline(always)] - fn hash_and_shard(&self, q: &Q) -> (u64, &RwLock>) + fn hash_and_shard(&self, q: &Q) -> (u64, &RwLock>) where T: Borrow, Q: ?Sized + Hash, @@ -348,7 +348,7 @@ impl ShardedSet { write_lock } else { // Write contention. Try reading first to see if the entry already exists. - if let Some(t) = shard.read().get(hash, |other| q == other.borrow()) { + if let Some(t) = shard.read().find(hash, |other| q == other.borrow()) { // Already exists. return Ok(t.clone()); } @@ -359,7 +359,7 @@ impl ShardedSet { // checked in the write contention case above. We don't use an // upgradable read lock because those are exclusive from one another // just like write locks. - if let Some(t) = shard.get(hash, |other| q == other.borrow()) { + if let Some(t) = shard.find(hash, |other| q == other.borrow()) { return Ok(t.clone()); } Err(InsertLock { @@ -378,15 +378,17 @@ impl ShardedSet { let (hash, shard) = self.hash_and_shard(q); shard .read() - .get(hash, |other| q == other.borrow()) - .map(Clone::clone) + .find(hash, |other| q == other.borrow()) + .cloned() } /// Unconditionally insert `t` without checking if it's in the set. pub fn unchecked_insert(&self, t: T) { let build_hasher = &self.build_hasher; let (hash, shard) = self.hash_and_shard(&t); - shard.write().insert(hash, t, |v| hash_one(build_hasher, v)); + shard + .write() + .insert_unique(hash, t, |v| hash_one(build_hasher, v)); } } @@ -396,6 +398,6 @@ impl InsertLock<'_, T, S> { pub fn insert>(&mut self, q: Q) { let build_hasher = self.build_hasher; self.shard - .insert(self.hash, q.into(), |v| hash_one(build_hasher, v)); + .insert_unique(self.hash, q.into(), |v| hash_one(build_hasher, v)); } } diff --git a/compiler/crates/intern/src/string.rs b/compiler/crates/intern/src/string.rs index b4cf020abe1c2..9e155b93ee583 100644 --- a/compiler/crates/intern/src/string.rs +++ b/compiler/crates/intern/src/string.rs @@ -380,7 +380,6 @@ mod tests { use std::sync::atomic::Ordering; use std::sync::Arc; use std::thread; - use std::u32; use rand::thread_rng; use rand::Rng; diff --git a/compiler/crates/interner/Cargo.toml b/compiler/crates/interner/Cargo.toml index f5e510d01beda..4e6f1be384fc4 100644 --- a/compiler/crates/interner/Cargo.toml +++ b/compiler/crates/interner/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" [dependencies] fnv = "1.0" -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } once_cell = "1.12" parking_lot = { version = "0.12.1", features = ["send_guard"] } serde = { version = "1.0.185", features = ["derive", "rc"] } diff --git a/compiler/crates/interner/src/bytes.rs b/compiler/crates/interner/src/bytes.rs index 787a2e9138a42..d39b6202b9992 100644 --- a/compiler/crates/interner/src/bytes.rs +++ b/compiler/crates/interner/src/bytes.rs @@ -88,7 +88,7 @@ impl Ord for StringKey { impl PartialOrd for StringKey { fn partial_cmp(&self, other: &Self) -> Option { - self.lookup().partial_cmp(other.lookup()) + Some(self.lookup().cmp(other.lookup())) } } diff --git a/compiler/crates/js-config-loader/Cargo.toml b/compiler/crates/js-config-loader/Cargo.toml index 2796fa2efd5e6..6f2fd32374a49 100644 --- a/compiler/crates/js-config-loader/Cargo.toml +++ b/compiler/crates/js-config-loader/Cargo.toml @@ -14,8 +14,8 @@ path = "tests/lib.rs" [dependencies] serde = { version = "1.0.185", features = ["derive", "rc"] } -serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } -thiserror = "1.0.64" +serde_json = { version = "1.0.140", features = ["float_roundtrip", "unbounded_depth"] } +thiserror = "2" [dev-dependencies] -tempfile = "3.8" +tempfile = "3.15" diff --git a/compiler/crates/persist-query/Cargo.toml b/compiler/crates/persist-query/Cargo.toml index 7bd691f27e616..690364db310b1 100644 --- a/compiler/crates/persist-query/Cargo.toml +++ b/compiler/crates/persist-query/Cargo.toml @@ -12,8 +12,8 @@ license = "MIT" hyper = { version = "0.14.26", features = ["client", "http1", "http2", "stream"] } hyper-tls = "0.5" serde = { version = "1.0.185", features = ["derive", "rc"] } -serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } -thiserror = "1.0.64" +serde_json = { version = "1.0.140", features = ["float_roundtrip", "unbounded_depth"] } +thiserror = "2" url = "2.5.2" [features] diff --git a/compiler/crates/relay-bin/Cargo.toml b/compiler/crates/relay-bin/Cargo.toml index 0366395f8ec5a..93e3ff12dd3f6 100644 --- a/compiler/crates/relay-bin/Cargo.toml +++ b/compiler/crates/relay-bin/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/facebook/relay" license = "MIT" [dependencies] -clap = { version = "4.5.20", features = ["derive", "env", "string", "unicode", "wrap_help"] } +clap = { version = "4.5.30", features = ["derive", "env", "string", "unicode", "wrap_help"] } common = { path = "../common" } intern = { path = "../intern" } log = { version = "0.4.22", features = ["kv_unstable"] } @@ -19,5 +19,5 @@ relay-lsp = { path = "../relay-lsp" } schema = { path = "../schema" } schema-documentation = { path = "../schema-documentation" } simplelog = "0.12.2" -thiserror = "1.0.64" +thiserror = "2" tokio = { version = "1.41.0", features = ["full", "test-util", "tracing"] } diff --git a/compiler/crates/relay-bin/src/main.rs b/compiler/crates/relay-bin/src/main.rs index 0db30cc593385..a5eba3926fc7f 100644 --- a/compiler/crates/relay-bin/src/main.rs +++ b/compiler/crates/relay-bin/src/main.rs @@ -285,6 +285,7 @@ async fn handle_codemod_command(command: CodemodCommand) -> Result<(), Error> { let mut config = get_config(command.config)?; set_project_flag(&mut config, command.projects)?; let (programs, _, config) = get_programs(config, Arc::new(ConsoleLogger)).await; + let programs = programs.values().cloned().collect(); match run_codemod(programs, Arc::clone(&config), command.codemod).await { Ok(_) => Ok(()), diff --git a/compiler/crates/relay-codegen/Cargo.toml b/compiler/crates/relay-codegen/Cargo.toml index 1b60e1afcf838..5b856e00c8557 100644 --- a/compiler/crates/relay-codegen/Cargo.toml +++ b/compiler/crates/relay-codegen/Cargo.toml @@ -46,10 +46,10 @@ docblock-shared = { path = "../docblock-shared" } fnv = "1.0" graphql-ir = { path = "../graphql-ir" } graphql-syntax = { path = "../graphql-syntax" } -hex = "0.4.3" +hex = { version = "0.4.3", features = ["alloc"] } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } md-5 = "0.10" relay-config = { path = "../relay-config" } relay-transforms = { path = "../relay-transforms" } diff --git a/compiler/crates/relay-codegen/src/ast.rs b/compiler/crates/relay-codegen/src/ast.rs index f0ec76f38939d..ed9e57e27a849 100644 --- a/compiler/crates/relay-codegen/src/ast.rs +++ b/compiler/crates/relay-codegen/src/ast.rs @@ -97,6 +97,12 @@ pub enum GraphQLModuleDependency { }, } +#[derive(Eq, PartialEq, Hash, Debug)] +pub enum ResolverJSFunction { + Module(JSModuleDependency), + PropertyLookup(String), +} + #[derive(Eq, PartialEq, Hash, Debug)] pub enum Primitive { Key(AstKey), @@ -122,7 +128,7 @@ pub enum Primitive { RelayResolverModel { graphql_module_name: StringKey, graphql_module_path: StringKey, - js_module: JSModuleDependency, + resolver_fn: ResolverJSFunction, injected_field_name_details: Option<(StringKey, bool)>, }, } @@ -189,7 +195,7 @@ pub struct RequestParameters<'a> { pub text: Option, } -impl<'a> RequestParameters<'a> { +impl RequestParameters<'_> { pub fn is_client_request(&self) -> bool { self.id.is_none() && self.text.is_none() } diff --git a/compiler/crates/relay-codegen/src/build_ast.rs b/compiler/crates/relay-codegen/src/build_ast.rs index ae3a19b629739..60d04203ab604 100644 --- a/compiler/crates/relay-codegen/src/build_ast.rs +++ b/compiler/crates/relay-codegen/src/build_ast.rs @@ -11,8 +11,8 @@ use ::intern::intern; use ::intern::string_key::Intern; use ::intern::string_key::StringKey; use ::intern::Lookup; +use common::ArgumentName; use common::DirectiveName; -use common::FeatureFlag; use common::NamedItem; use common::ObjectName; use common::WithLocation; @@ -39,6 +39,7 @@ use graphql_syntax::OperationKind; use lazy_static::lazy_static; use md5::Digest; use md5::Md5; +use relay_config::DynamicModuleProvider; use relay_config::JsModuleFormat; use relay_config::ProjectConfig; use relay_config::Surface; @@ -52,6 +53,7 @@ use relay_transforms::get_resolver_fragment_dependency_name; use relay_transforms::relay_resolvers::get_resolver_info; use relay_transforms::relay_resolvers::resolver_import_alias; use relay_transforms::relay_resolvers::ResolverInfo; +use relay_transforms::relay_resolvers::ResolverSchemaGenType; use relay_transforms::remove_directive; use relay_transforms::CatchMetadataDirective; use relay_transforms::ClientEdgeMetadata; @@ -94,6 +96,7 @@ use crate::ast::ObjectEntry; use crate::ast::Primitive; use crate::ast::QueryID; use crate::ast::RequestParameters; +use crate::ast::ResolverJSFunction; use crate::ast::ResolverModuleReference; use crate::constants::CODEGEN_CONSTANTS; use crate::object; @@ -103,6 +106,9 @@ lazy_static! { DirectiveName("throwOnFieldError".intern()); pub static ref EXEC_TIME_RESOLVERS: DirectiveName = DirectiveName("exec_time_resolvers".intern()); + static ref EXEC_TIME_RESOLVERS_ENABLED_ARGUMENT: ArgumentName = + ArgumentName("enabledProvider".intern()); + static ref FRAGMENT_KEY: StringKey = "fragment".intern(); } pub fn build_request_params_ast_key( @@ -368,21 +374,70 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { let feature_flags = &self.project_config.feature_flags; feature_flags.enable_resolver_normalization_ast || (feature_flags.enable_exec_time_resolvers_directive - && context.has_exec_time_resolvers_directive) + && context.has_exec_time_resolvers_directive + && !context.has_exec_time_resolvers_enabled_provider) + } + + fn use_exec_and_read_time_resolvers(&self, context: &ContextualMetadata) -> bool { + let feature_flags = &self.project_config.feature_flags; + feature_flags.enable_exec_time_resolvers_directive + && context.has_exec_time_resolvers_directive + && context.has_exec_time_resolvers_enabled_provider } fn build_operation(&mut self, operation: &OperationDefinition) -> AstKey { + let has_exec_time_resolvers_directive = + operation.directives.named(*EXEC_TIME_RESOLVERS).is_some(); + let exec_time_resolvers_enabled_provider = operation + .directives + .named(*EXEC_TIME_RESOLVERS) + .and_then(|directive| { + directive + .arguments + .named(*EXEC_TIME_RESOLVERS_ENABLED_ARGUMENT) + .map(|arg| match &arg.value.item { + Value::Constant(ConstantValue::String(cons)) => WithLocation { + item: *cons, + location: arg.value.location, + }, + _ => panic!( + "The enabled argument in exec_time_resolvers directive should be the string name of your provider file." + ), + }) + }); + + let exec_time_resolvers_field = if has_exec_time_resolvers_directive { + if let Some(provider) = exec_time_resolvers_enabled_provider { + let mut provider_path = PathBuf::from(provider.location.source_location().path()); + provider_path.pop(); + provider_path.push(PathBuf::from(provider.item.lookup())); + let artifact_path = self + .project_config + .artifact_path_for_definition(self.definition_source_location); + Some(ObjectEntry { + key: "exec_time_resolvers_enabled_provider".intern(), + value: Primitive::JSModuleDependency(JSModuleDependency { + path: self + .project_config + .js_module_import_identifier(&artifact_path, &provider_path), + import_name: ModuleImportName::Default(provider.item), + }), + }) + } else { + Some(ObjectEntry { + key: "use_exec_time_resolvers".intern(), + value: Primitive::Bool(true), + }) + } + } else { + None + }; let mut context = ContextualMetadata { has_client_edges: false, - has_exec_time_resolvers_directive: operation - .directives - .named(*EXEC_TIME_RESOLVERS) + has_exec_time_resolvers_directive, + has_exec_time_resolvers_enabled_provider: exec_time_resolvers_enabled_provider .is_some(), }; - let exec_time_resolvers_field = ObjectEntry { - key: "use_exec_time_resolvers".intern(), - value: Primitive::Bool(context.has_exec_time_resolvers_directive), - }; match operation.directives.named(*DIRECTIVE_SPLIT_OPERATION) { Some(_split_directive) => { let metadata = Primitive::Key(self.object(vec![])); @@ -394,7 +449,7 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { selections: selections, }; if context.has_exec_time_resolvers_directive { - fields.push(exec_time_resolvers_field); + fields.push(exec_time_resolvers_field.unwrap()); } if !operation.variable_definitions.is_empty() { let argument_definitions = @@ -420,7 +475,7 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { selections: selections, }; if context.has_exec_time_resolvers_directive { - fields.push(exec_time_resolvers_field); + fields.push(exec_time_resolvers_field.unwrap()); } if let Some(client_abstract_types) = self.maybe_build_client_abstract_types(operation) @@ -843,19 +898,34 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { { self.build_normalization_relay_resolver_execution_time_for_worker(resolver_metadata) } else if self.use_exec_time_resolvers(context) { - self.build_normalization_relay_resolver_execution_time(resolver_metadata) + self.build_normalization_relay_resolver_exec_and_read_time( + resolver_metadata, + inline_fragment, + true, + ) + } else if self.use_exec_and_read_time_resolvers(context) { + // We must handle both read time resolvers case and exec time resolvers case + // since the mode it is in (read time resolvers vs exec time resolvers) + // is now determined at runtime. + self.build_normalization_relay_resolver_exec_and_read_time( + resolver_metadata, + inline_fragment, + false, + ) } else { self.build_normalization_relay_resolver_read_time(resolver_metadata, inline_fragment) } } - // For read time execution time Relay Resolvers in the normalization AST, - // we do not need to include resolver modules since those modules will be - // evaluated at read time. - fn build_normalization_relay_resolver_read_time( + // This function generates a Normalization AST node that is the UNION of the node that would be + // generated for the exec time resolvers case and the node that would be generated for the read + // time resolvers case. This is because we need information to fulfill requests for both cases + // in the runtime now, since the query's mode is determined dynamically at runtime. + fn build_normalization_relay_resolver_exec_and_read_time( &mut self, resolver_metadata: &RelayResolverMetadata, inline_fragment: Option, + exec_resolvers_only: bool, ) -> Primitive { let field_name = resolver_metadata.field_name(self.schema); let field_arguments = &resolver_metadata.field_arguments; @@ -863,17 +933,36 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { let is_output_type = resolver_metadata .output_type_info .normalization_ast_should_have_is_output_type_true(); - Primitive::Key(self.object(object! { + let kind = if resolver_metadata.live { + CODEGEN_CONSTANTS.relay_live_resolver + } else { + CODEGEN_CONSTANTS.relay_resolver + }; + let variable_name = resolver_metadata.generate_local_resolver_name(self.schema); + let artifact_path = &self + .project_config + .artifact_path_for_definition(self.definition_source_location); + let resolver_info = build_resolver_info( + self.ast_builder, + self.project_config, + artifact_path, + self.schema.field(resolver_metadata.field_id), + resolver_metadata.import_path, + match resolver_metadata.import_name { + Some(name) => ModuleImportName::Named { + name, + import_as: Some(variable_name), + }, + None => ModuleImportName::Default(variable_name), + }, + ); + let mut obj = object! { name: Primitive::String(field_name), args: match args { None => Primitive::SkippableNull, Some(key) => Primitive::Key(key), }, - fragment: match inline_fragment { - None => Primitive::SkippableNull, - Some(fragment) => fragment, - }, - kind: Primitive::String(CODEGEN_CONSTANTS.relay_resolver), + kind: Primitive::String(kind), storage_key: match args { None => Primitive::SkippableNull, Some(key) => { @@ -885,17 +974,27 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { } }, is_output_type: Primitive::Bool(is_output_type), - })) + resolver_info: Primitive::Key(resolver_info), + }; + if !exec_resolvers_only { + obj.push(ObjectEntry { + key: *FRAGMENT_KEY, + value: match inline_fragment { + None => Primitive::SkippableNull, + Some(fragment) => fragment, + }, + }); + } + Primitive::Key(self.object(obj)) } - // For execution time Relay Resolvers in the normalization AST, we need to - // also include enough information for resolver function backing each field, - // so that normalization AST have full information on how to resolve client - // edges and fields. That means we need to include the resolver module. Note - // that we don't support inline fragment as we did for read time resolvers - fn build_normalization_relay_resolver_execution_time( + // For read time Relay Resolvers in the normalization AST, we do not + // need to include resolver modules since those modules will be + // evaluated at read time. + fn build_normalization_relay_resolver_read_time( &mut self, resolver_metadata: &RelayResolverMetadata, + inline_fragment: Option, ) -> Primitive { let field_name = resolver_metadata.field_name(self.schema); let field_arguments = &resolver_metadata.field_arguments; @@ -903,38 +1002,17 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { let is_output_type = resolver_metadata .output_type_info .normalization_ast_should_have_is_output_type_true(); - - let variable_name = resolver_metadata.generate_local_resolver_name(self.schema); - let artifact_path = &self - .project_config - .artifact_path_for_definition(self.definition_source_location); - let kind = if resolver_metadata.live { - CODEGEN_CONSTANTS.relay_live_resolver - } else { - CODEGEN_CONSTANTS.relay_resolver - }; - let resolver_info = build_resolver_info( - self.ast_builder, - self.project_config, - artifact_path, - self.schema.field(resolver_metadata.field_id), - resolver_metadata.import_path, - match resolver_metadata.import_name { - Some(name) => ModuleImportName::Named { - name, - import_as: Some(variable_name), - }, - None => ModuleImportName::Default(variable_name), - }, - ); - Primitive::Key(self.object(object! { name: Primitive::String(field_name), args: match args { None => Primitive::SkippableNull, Some(key) => Primitive::Key(key), }, - kind: Primitive::String(kind), + fragment: match inline_fragment { + None => Primitive::SkippableNull, + Some(fragment) => fragment, + }, + kind: Primitive::String(CODEGEN_CONSTANTS.relay_resolver), storage_key: match args { None => Primitive::SkippableNull, Some(key) => { @@ -946,7 +1024,6 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { } }, is_output_type: Primitive::Bool(is_output_type), - resolver_info: Primitive::Key(resolver_info), })) } @@ -1449,6 +1526,7 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { }, )), type_confirmed: relay_resolver_metadata.type_confirmed, + resolver_type: ResolverSchemaGenType::ResolverModule, }; let fragment_primitive = Primitive::Key(self.object(object! { args: Primitive::SkippableNull, @@ -1534,10 +1612,19 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { ), ); + let resolver_fn = match relay_resolver_metadata.resolver_type { + ResolverSchemaGenType::ResolverModule => { + ResolverJSFunction::Module(resolver_js_module) + } + ResolverSchemaGenType::PropertyLookup { property_name } => { + ResolverJSFunction::PropertyLookup(property_name.to_string()) + } + }; + Primitive::RelayResolverModel { graphql_module_name: fragment_name.item.0, graphql_module_path: fragment_import_path, - js_module: resolver_js_module, + resolver_fn, injected_field_name_details: match injection_mode { FragmentDataInjectionMode::Field { name, is_required } => { Some((name, is_required)) @@ -1751,13 +1838,17 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { }) } - fn build_client_edge_with_enabled_resolver_normalization_ast( + // This function creates a node that is the UNION of the nodes that would be created for read time resolvers + // and for exec time resolvers (so runtime has ALL the information it needs to run for both resolver modes.) + // Surprisingly, this function can stay exactly the same as build_client_edge_with_enabled_resolver_normalization_ast + // (the function for exec time resolver nodes). + fn build_client_edge_exec_and_read_time( &mut self, context: &mut ContextualMetadata, client_edge_metadata: ClientEdgeMetadata<'_>, ) -> Primitive { let backing_field_primitives = - self.build_selections_from_selection(context, &client_edge_metadata.backing_field); + self.build_selections_from_selection(context, client_edge_metadata.backing_field); if backing_field_primitives.len() != 1 { panic!( @@ -1825,7 +1916,7 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { client_edge_metadata: ClientEdgeMetadata<'_>, ) -> Primitive { let backing_field_primitives = - self.build_selections_from_selection(context, &client_edge_metadata.backing_field); + self.build_selections_from_selection(context, client_edge_metadata.backing_field); if backing_field_primitives.len() != 1 { panic!( @@ -1994,8 +2085,13 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { ) } CodegenVariant::Normalization => { - if self.use_exec_time_resolvers(context) { - self.build_client_edge_with_enabled_resolver_normalization_ast( + // In this case, the functions we run for exec time mode only and for exec and read time mode + // are the exact same. This is because the node fields for read time is a subset of the node + // fields for exec time. + if self.use_exec_time_resolvers(context) + || self.use_exec_and_read_time_resolvers(context) + { + self.build_client_edge_exec_and_read_time( context, client_edge_metadata, ) @@ -2382,17 +2478,11 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { kind: Primitive::String(CODEGEN_CONSTANTS.module_import), }; - let should_use_reader_module_imports = - match &self.project_config.feature_flags.use_reader_module_imports { - FeatureFlag::Enabled => true, - FeatureFlag::Disabled => false, - FeatureFlag::Limited { - allowlist: fragment_names, - } => fragment_names.contains(&module_metadata.key), - FeatureFlag::Rollout { rollout } => { - rollout.check(module_metadata.key.lookup().as_bytes()) - } - }; + let should_use_reader_module_imports = self + .project_config + .feature_flags + .use_reader_module_imports + .is_enabled_for(module_metadata.key); match self.variant { CodegenVariant::Reader => { @@ -2413,9 +2503,6 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { } } CodegenVariant::Normalization => { - if module_metadata.read_time_resolvers { - return vec![]; - } if let Some(dynamic_module_provider) = self .project_config .module_import_config @@ -2438,7 +2525,67 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { }, }); } - Some(Surface::Resolvers) => {} + Some(Surface::Resolvers) => { + if module_metadata.read_time_resolvers { + module_import.push(ObjectEntry { + key: CODEGEN_CONSTANTS.component_module_provider, + value: Primitive::DynamicImport { + provider: dynamic_module_provider, + module: module_metadata.module_name, + }, + }); + match dynamic_module_provider { + DynamicModuleProvider::JSResource => { + module_import.push(ObjectEntry { + key: CODEGEN_CONSTANTS.operation_module_provider, + value: Primitive::DynamicImport { + provider: dynamic_module_provider, + module: get_normalization_fragment_filename( + fragment_name, + ), + }, + }); + } + DynamicModuleProvider::Custom { .. } => { + let custom_dynamic_module_provider = + match self.project_config.js_module_format { + JsModuleFormat::Haste => dynamic_module_provider, + _ => { + let path = self + .project_config + .create_path_for_artifact( + module_metadata + .fragment_source_location + .source_location(), + fragment_name.0.to_string(), + ); + let path_for_module = + path.display().to_string().replace( + &fragment_name.0.to_string(), + "<$module>", + ); + DynamicModuleProvider::Custom { + statement: format!( + "() => require('{}')", + path_for_module + ) + .intern(), + } + } + }; + module_import.push(ObjectEntry { + key: CODEGEN_CONSTANTS.operation_module_provider, + value: Primitive::DynamicImport { + provider: custom_dynamic_module_provider, + module: get_normalization_fragment_filename( + fragment_name, + ), + }, + }); + } + }; + } + } } } } @@ -2738,4 +2885,5 @@ pub fn md5(data: &str) -> String { struct ContextualMetadata { has_client_edges: bool, has_exec_time_resolvers_directive: bool, + has_exec_time_resolvers_enabled_provider: bool, } diff --git a/compiler/crates/relay-codegen/src/printer.rs b/compiler/crates/relay-codegen/src/printer.rs index ec25bac2badea..489bfbae4ca9f 100644 --- a/compiler/crates/relay-codegen/src/printer.rs +++ b/compiler/crates/relay-codegen/src/printer.rs @@ -13,17 +13,20 @@ use std::path::Path; use fnv::FnvBuildHasher; use fnv::FnvHashSet; -use graphql_ir::reexport::Intern; use graphql_ir::ExecutableDefinitionName; use graphql_ir::FragmentDefinition; use graphql_ir::OperationDefinition; +use graphql_ir::reexport::Intern; use indexmap::IndexMap; -use intern::string_key::StringKey; use intern::Lookup; +use intern::string_key::StringKey; use relay_config::DynamicModuleProvider; use relay_config::ProjectConfig; use schema::SDLSchema; +use crate::CodegenBuilder; +use crate::CodegenVariant; +use crate::JsModuleFormat; use crate::ast::Ast; use crate::ast::AstBuilder; use crate::ast::AstKey; @@ -34,6 +37,7 @@ use crate::ast::ObjectEntry; use crate::ast::Primitive; use crate::ast::QueryID; use crate::ast::RequestParameters; +use crate::ast::ResolverJSFunction; use crate::ast::ResolverModuleReference; use crate::build_ast::build_fragment; use crate::build_ast::build_operation; @@ -49,9 +53,6 @@ use crate::object; use crate::top_level_statements::TopLevelStatement; use crate::top_level_statements::TopLevelStatements; use crate::utils::escape; -use crate::CodegenBuilder; -use crate::CodegenVariant; -use crate::JsModuleFormat; pub fn print_operation( schema: &SDLSchema, @@ -547,7 +548,9 @@ impl<'b> JSONPrinter<'b> { }; self.write_js_dependency( f, - ModuleImportName::Default(format!("rescript_graphql_node_{}", variable_name).intern()), + ModuleImportName::Default( + format!("rescript_graphql_node_{}", variable_name).intern(), + ), Cow::Owned(format!( "rescript_graphql_node_{}", get_module_path(self.js_module_format, *key) @@ -555,27 +558,29 @@ impl<'b> JSONPrinter<'b> { ) } Primitive::JSModuleDependency(JSModuleDependency { path, import_name }) => { - let write_js_dependency = self - .write_js_dependency( - f, - match import_name { - ModuleImportName::Default(_) => ModuleImportName::Default(format!( - "rescript_module_{}", - common::rescript_utils::get_module_name_from_file_path( - &path.to_string().as_str() - ) - ).intern()), - o => o.clone() - }, - Cow::Owned(format!( - "rescript_module_{}", - common::rescript_utils::get_module_name_from_file_path( - &path.to_string().as_str() - ) - )), - ); + let write_js_dependency = self.write_js_dependency( + f, + match import_name { + ModuleImportName::Default(_) => ModuleImportName::Default( + format!( + "rescript_module_{}", + common::rescript_utils::get_module_name_from_file_path( + &path.to_string().as_str() + ) + ) + .intern(), + ), + o => o.clone(), + }, + Cow::Owned(format!( + "rescript_module_{}", + common::rescript_utils::get_module_name_from_file_path( + &path.to_string().as_str() + ) + )), + ); write_js_dependency - }, + } Primitive::ResolverModuleReference(ResolverModuleReference { field_type, resolver_function_name, @@ -604,13 +609,13 @@ impl<'b> JSONPrinter<'b> { Primitive::RelayResolverModel { graphql_module_path, graphql_module_name, - js_module, + resolver_fn, injected_field_name_details, } => self.write_relay_resolver_model( f, *graphql_module_name, *graphql_module_path, - js_module, + resolver_fn, injected_field_name_details.as_ref().copied(), ), } @@ -671,7 +676,6 @@ impl<'b> JSONPrinter<'b> { } else { write!(f, "{}.{}", path, name) } - } } } @@ -682,7 +686,7 @@ impl<'b> JSONPrinter<'b> { f: &mut String, graphql_module_name: StringKey, graphql_module_path: StringKey, - js_module: &JSModuleDependency, + resolver_fn: &ResolverJSFunction, injected_field_name_details: Option<(StringKey, bool)>, ) -> FmtResult { let relay_runtime_experimental = "relay-runtime/experimental"; @@ -699,18 +703,28 @@ impl<'b> JSONPrinter<'b> { write!(f, "(")?; self.write_js_dependency( f, - ModuleImportName::Default(format!("rescript_graphql_node_{}", graphql_module_name).intern()), + ModuleImportName::Default( + format!("rescript_graphql_node_{}", graphql_module_name).intern(), + ), Cow::Owned(format!( "rescript_graphql_node_{}", get_module_path(self.js_module_format, graphql_module_path) )), )?; write!(f, ", ")?; - self.write_js_dependency( - f, - js_module.import_name.clone(), - Cow::Owned(format!("rescript_module_{}", get_module_path(self.js_module_format, js_module.path))), - )?; + match resolver_fn { + ResolverJSFunction::Module(js_module) => self.write_js_dependency( + f, + js_module.import_name.clone(), + Cow::Owned(format!( + "rescript_module_{}", + get_module_path(self.js_module_format, js_module.path) + )), + )?, + ResolverJSFunction::PropertyLookup(property) => { + write_arrow_fn(f, &["o"], &format!("o.{}", property))? + } + } if let Some((field_name, is_required_field)) = injected_field_name_details { write!(f, ", '{}'", field_name)?; write!(f, ", {}", is_required_field)?; @@ -719,6 +733,11 @@ impl<'b> JSONPrinter<'b> { } } +fn write_arrow_fn(f: &mut String, params: &[&str], body: &str) -> FmtResult { + write!(f, "({}) => {}", params.join(", "), body)?; + Ok(()) +} + pub fn get_module_path(js_module_format: JsModuleFormat, key: StringKey) -> Cow<'static, str> { match js_module_format { JsModuleFormat::CommonJS => { diff --git a/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.expected b/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.expected index a74f18e606e3b..87a5e0ea62cd6 100644 --- a/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.expected +++ b/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.expected @@ -1,7 +1,7 @@ ==================================== INPUT ==================================== # enable-exec-time-resolvers-directive -query Foo @exec_time_resolvers { +query Foo @exec_time_resolvers(enabledProvider: "execTimeResolversFlagProvider") { me { pet { name @@ -54,7 +54,8 @@ extend type User { "resolverInfo": { "resolverFunction": require('PetResolver').Pet, "rootFragment": null - } + }, + "fragment": null }, "linkedField": { "alias": null, @@ -73,7 +74,8 @@ extend type User { "resolverInfo": { "resolverFunction": require('CatNameResolver').name, "rootFragment": null - } + }, + "fragment": null } ], "storageKey": null @@ -83,5 +85,5 @@ extend type User { "storageKey": null } ], - "use_exec_time_resolvers": true + "exec_time_resolvers_enabled_provider": require('execTimeResolversFlagProvider') } diff --git a/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.graphql b/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.graphql index 98a9f7822a4c6..72efa8d50a502 100644 --- a/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.graphql +++ b/compiler/crates/relay-codegen/tests/client_edges/fixtures/client-edge-exec-time-resolver.graphql @@ -1,6 +1,6 @@ # enable-exec-time-resolvers-directive -query Foo @exec_time_resolvers { +query Foo @exec_time_resolvers(enabledProvider: "execTimeResolversFlagProvider") { me { pet { name diff --git a/compiler/crates/relay-codemod/Cargo.toml b/compiler/crates/relay-codemod/Cargo.toml index 3f4372fb73a12..296c382903394 100644 --- a/compiler/crates/relay-codemod/Cargo.toml +++ b/compiler/crates/relay-codemod/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/facebook/relay" license = "MIT" [dependencies] -clap = { version = "4.5.20", features = ["derive", "env", "string", "unicode", "wrap_help"] } +clap = { version = "4.5.30", features = ["derive", "env", "string", "unicode", "wrap_help"] } common = { path = "../common" } log = { version = "0.4.22", features = ["kv_unstable"] } lsp-types = "0.94.1" diff --git a/compiler/crates/relay-codemod/src/codemod.rs b/compiler/crates/relay-codemod/src/codemod.rs index e61f6f6e41810..da1a1f5b54664 100644 --- a/compiler/crates/relay-codemod/src/codemod.rs +++ b/compiler/crates/relay-codemod/src/codemod.rs @@ -12,6 +12,7 @@ use clap::Args; use clap::Subcommand; use common::FeatureFlag; use common::Rollout; +use common::RolloutRange; use log::info; use lsp_types::CodeActionOrCommand; use lsp_types::TextEdit; @@ -32,9 +33,11 @@ pub enum AvailableCodemod { #[derive(Args, Debug, Clone)] pub struct MarkDangerousConditionalFragmentSpreadsArgs { - /// If using a feature flag, specify the rollout percentage. If omitted, the codemod is fully enabled. - #[clap(long, short, value_parser=valid_percent)] - pub rollout_percentage: Option, + /// Specify a percentage of fragments to codemod. If a number is provided, + /// the first n percentage of fragments will be codemodded. If a range (`20-30`) is + /// provided, then fragments between the start and end of the range will be codemodded. + #[clap(long, short, value_parser=valid_percent, default_value = "100")] + pub rollout_percentage: FeatureFlag, } pub async fn run_codemod( @@ -46,19 +49,16 @@ pub async fn run_codemod( .iter() .flat_map(|programs| match &codemod { AvailableCodemod::MarkDangerousConditionalFragmentSpreads(opts) => { - match fragment_alias_directive( - &programs.source, - &FeatureFlag::Rollout { - rollout: Rollout(opts.rollout_percentage), - }, - ) { + match fragment_alias_directive(&programs.source, &opts.rollout_percentage) { Ok(_) => vec![], Err(e) => e, } } AvailableCodemod::RemoveUnnecessaryRequiredDirectives => { - disallow_required_on_non_null_field(&programs.source.schema, &programs.source) - .unwrap_or_default() + match disallow_required_on_non_null_field(&programs.reader) { + Ok(_) => vec![], + Err(e) => e, + } } }) .collect::>(); @@ -144,13 +144,33 @@ fn sort_changes(url: &Url, changes: &mut Vec) -> Result<(), std::io::E Ok(()) } -fn valid_percent(s: &str) -> Result { - // turn s into a u8 - let s = s.parse::().map_err(|_| "not a number".to_string())?; - // check if s is less than 100 - if (0..=100).contains(&s) { - Ok(s) +fn valid_percent(s: &str) -> Result { + // If the string is a range of the form "x-y", where x and y are numbers, return the range + let parts: Vec<&str> = s.split('-').collect(); + if parts.len() == 2 { + let start = parts[0].parse::().map_err(|_| { + "Expected the value on the left of the rollout range to be a number".to_string() + })?; + let end = parts[1].parse::().map_err(|_| { + "Expected the value on the right of the rollout range to be a number".to_string() + })?; + if (0..=100).contains(&start) && (0..=100).contains(&end) && start <= end { + Ok(FeatureFlag::RolloutRange { + rollout: RolloutRange { start, end }, + }) + } else { + Err("numbers must be between 0 and 100, inclusive, and the first number must be less than or equal to the second".to_string()) + } } else { - Err("number must be between 0 and 100, inclusive".to_string()) + // turn s into a u8 + let s = s.parse::().map_err(|_| "not a number".to_string())?; + // check if s is less than 100 + if (0..=100).contains(&s) { + Ok(FeatureFlag::Rollout { + rollout: Rollout(Some(s)), + }) + } else { + Err("number must be between 0 and 100, inclusive".to_string()) + } } } diff --git a/compiler/crates/relay-compiler/Cargo.toml b/compiler/crates/relay-compiler/Cargo.toml index 56640a27a6c1e..313238f589f3a 100644 --- a/compiler/crates/relay-compiler/Cargo.toml +++ b/compiler/crates/relay-compiler/Cargo.toml @@ -25,7 +25,7 @@ name = "relay_compiler_relay_config_schema_json_test" path = "tests/relay_config_schema_json_test.rs" [dependencies] -async-trait = "0.1.71" +async-trait = "0.1.86" bincode = "1.3.3" common = { path = "../common" } common-path = "1.0.0" @@ -45,17 +45,17 @@ graphql-ir = { path = "../graphql-ir" } graphql-syntax = { path = "../graphql-syntax" } graphql-text-printer = { path = "../graphql-text-printer" } graphql-watchman = { path = "../graphql-watchman" } -hex = "0.4.3" +hex = { version = "0.4.3", features = ["alloc"] } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } intern = { path = "../intern" } js-config-loader = { path = "../js-config-loader" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } log = { version = "0.4.22", features = ["kv_unstable"] } md-5 = "0.10" persist-query = { path = "../persist-query" } petgraph = { version = "0.6.3", features = ["serde-1"] } rayon = "1.9.0" -regex = "1.9.2" +regex = "1.11.1" relay-codegen = { path = "../relay-codegen" } relay-config = { path = "../relay-config" } relay-docblock = { path = "../relay-docblock" } @@ -63,25 +63,25 @@ relay-saved-state-loader = { path = "../relay-saved-state-loader" } relay-schema = { path = "../relay-schema" } relay-transforms = { path = "../relay-transforms" } relay-typegen = { path = "../relay-typegen" } -rustc-hash = "1.1.0" +rustc-hash = "2.1.0" schema = { path = "../schema" } schema-diff = { path = "../schema-diff" } schema-validate-lib = { path = "../schema-validate" } schemars = { version = "0.8.21", features = ["indexmap2"] } serde = { version = "1.0.185", features = ["derive", "rc"] } -serde_bser = "0.3" -serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } +serde_bser = "0.4" +serde_json = { version = "1.0.140", features = ["float_roundtrip", "unbounded_depth"] } sha1 = "0.10.5" sha2 = "0.10.6" signedsource = { path = "../signedsource" } -thiserror = "1.0.64" +thiserror = "2" tokio = { version = "1.41.0", features = ["full", "test-util", "tracing"] } walkdir = "2.3" -watchman_client = "0.8.0" +watchman_client = "0.9.0" zstd = { version = "0.13", features = ["experimental", "zstdmt"] } [dev-dependencies] fixture-tests = { path = "../fixture-tests" } -futures-util = "0.3.30" +futures-util = { version = "0.3.30", features = ["compat"] } graphql-test-helpers = { path = "../graphql-test-helpers" } relay-test-schema = { path = "../relay-test-schema" } diff --git a/compiler/crates/relay-compiler/relay-compiler-config-schema.json b/compiler/crates/relay-compiler/relay-compiler-config-schema.json index fdeff5cdd788c..cfa30c1a125ca 100644 --- a/compiler/crates/relay-compiler/relay-compiler-config-schema.json +++ b/compiler/crates/relay-compiler/relay-compiler-config-schema.json @@ -193,6 +193,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -279,6 +315,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -365,6 +437,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -451,6 +559,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -537,6 +681,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -623,6 +803,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -709,6 +925,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -795,6 +1047,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -840,7 +1128,7 @@ "enforce_fragment_alias_where_ambiguous": { "description": "Enforce that you must add `@alias` to a fragment if it may not match, due to type mismatch or `@skip`/`@include`", "default": { - "kind": "disabled" + "kind": "enabled" }, "oneOf": [ { @@ -920,6 +1208,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -1006,6 +1330,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -1092,20 +1452,56 @@ "minimum": 0.0 } } - } - ] - }, - "omit_resolver_type_assertions_for_confirmed_types": { - "description": "Skip generating resolver type assertions for resolvers which have been derived from TS/Flow types.", - "default": { - "kind": "disabled" - }, - "oneOf": [ + }, { - "description": "Fully disabled: developers may not use this feature", + "description": "Partially enabled: used for gradual rollout of the feature", "type": "object", "required": [ - "kind" + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } + } + ] + }, + "omit_resolver_type_assertions_for_confirmed_types": { + "description": "Skip generating resolver type assertions for resolvers which have been derived from TS/Flow types.", + "default": { + "kind": "disabled" + }, + "oneOf": [ + { + "description": "Fully disabled: developers may not use this feature", + "type": "object", + "required": [ + "kind" ], "properties": { "kind": { @@ -1178,6 +1574,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -1268,6 +1700,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -1353,6 +1821,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -1439,6 +1943,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -1525,6 +2065,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] } @@ -1845,6 +2421,7 @@ "streamName": "stream", "useCustomizedBatchArg": "useCustomizedBatch" }, + "enableTokenField": false, "nodeInterfaceIdField": "id", "nodeInterfaceIdVariableName": "id", "nonNodeIdFields": null, @@ -1946,6 +2523,11 @@ }, "additionalProperties": false }, + "enableTokenField": { + "description": "If we should select __token field on fetchable types", + "default": false, + "type": "boolean" + }, "nodeInterfaceIdField": { "description": "The name of the `id` field that exists on the `Node` interface.", "default": "id", @@ -2191,6 +2773,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2277,6 +2895,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2363,6 +3017,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2449,6 +3139,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2535,6 +3261,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2621,6 +3383,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2707,6 +3505,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2793,6 +3627,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -2838,7 +3708,7 @@ "enforce_fragment_alias_where_ambiguous": { "description": "Enforce that you must add `@alias` to a fragment if it may not match, due to type mismatch or `@skip`/`@include`", "default": { - "kind": "disabled" + "kind": "enabled" }, "oneOf": [ { @@ -2918,6 +3788,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -3004,6 +3910,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -3090,6 +4032,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -3163,17 +4141,53 @@ "kind": { "type": "string", "enum": [ - "rollout" + "rollout" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Can be constructed as the Default which passes or a percentage between 0 and 100.", + "type": [ + "integer", + "null" + ], + "format": "uint8", + "minimum": 0.0 + } + } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" ] }, "rollout": { - "description": "A utility to enable gradual rollout of large codegen changes. Can be constructed as the Default which passes or a percentage between 0 and 100.", - "type": [ - "integer", - "null" + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" ], - "format": "uint8", - "minimum": 0.0 + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } } } } @@ -3266,6 +4280,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -3351,6 +4401,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -3437,6 +4523,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -3523,6 +4645,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] } @@ -3832,6 +4990,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -3918,6 +5112,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4004,6 +5234,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4090,6 +5356,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4176,6 +5478,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4253,13 +5591,49 @@ ] }, "rollout": { - "description": "A utility to enable gradual rollout of large codegen changes. Can be constructed as the Default which passes or a percentage between 0 and 100.", - "type": [ - "integer", - "null" + "description": "A utility to enable gradual rollout of large codegen changes. Can be constructed as the Default which passes or a percentage between 0 and 100.", + "type": [ + "integer", + "null" + ], + "format": "uint8", + "minimum": 0.0 + } + } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" ], - "format": "uint8", - "minimum": 0.0 + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } } } } @@ -4348,6 +5722,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4434,6 +5844,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4479,7 +5925,7 @@ "enforce_fragment_alias_where_ambiguous": { "description": "Enforce that you must add `@alias` to a fragment if it may not match, due to type mismatch or `@skip`/`@include`", "default": { - "kind": "disabled" + "kind": "enabled" }, "oneOf": [ { @@ -4559,6 +6005,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4645,6 +6127,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4731,6 +6249,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4817,6 +6371,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4907,6 +6497,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -4992,6 +6618,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -5078,6 +6740,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] }, @@ -5164,6 +6862,42 @@ "minimum": 0.0 } } + }, + { + "description": "Partially enabled: used for gradual rollout of the feature", + "type": "object", + "required": [ + "kind", + "rollout" + ], + "properties": { + "kind": { + "type": "string", + "enum": [ + "rolloutrange" + ] + }, + "rollout": { + "description": "A utility to enable gradual rollout of large codegen changes. Allows you to specify a range of percentages to rollout.", + "type": "object", + "required": [ + "end", + "start" + ], + "properties": { + "end": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "start": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + } } ] } @@ -5486,6 +7220,7 @@ "streamName": "stream", "useCustomizedBatchArg": "useCustomizedBatch" }, + "enableTokenField": false, "nodeInterfaceIdField": "id", "nodeInterfaceIdVariableName": "id", "nonNodeIdFields": null, @@ -5587,6 +7322,11 @@ }, "additionalProperties": false }, + "enableTokenField": { + "description": "If we should select __token field on fetchable types", + "default": false, + "type": "boolean" + }, "nodeInterfaceIdField": { "description": "The name of the `id` field that exists on the `Node` interface.", "default": "id", diff --git a/compiler/crates/relay-compiler/src/build_project/artifact_writer.rs b/compiler/crates/relay-compiler/src/build_project/artifact_writer.rs index 44b0278be972b..fa212822f3423 100644 --- a/compiler/crates/relay-compiler/src/build_project/artifact_writer.rs +++ b/compiler/crates/relay-compiler/src/build_project/artifact_writer.rs @@ -15,6 +15,7 @@ use std::path::PathBuf; use std::sync::Mutex; use dashmap::DashSet; +use log::debug; use log::info; use sha1::Digest; use sha1::Sha1; @@ -104,7 +105,10 @@ impl ArtifactWriter for ArtifactFileWriter { Ok(_) => { self.removed.lock().unwrap().push(path); } - _ => info!("tried to delete already deleted file: {:?}", path), + Err(error) => { + info!("tried to delete already deleted file: {:?}", path); + debug!("[artifact_writer] error when deleting file: {:?}", error); + } } Ok(()) } diff --git a/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs b/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs index 4558eb8c63597..12c054254302f 100644 --- a/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs +++ b/compiler/crates/relay-compiler/src/build_project/generate_artifacts.rs @@ -57,7 +57,7 @@ pub fn generate_artifacts( ..Default::default() }; let mut operation_printer = OperationPrinter::new(&programs.operation_text, printer_options); - return group_operations(programs).into_values().map(|operations| { + group_operations(programs).into_values().map(|operations| { if let Some(normalization) = operations.normalization { // We have a normalization AST... so we'll move forward with that if let Some(metadata) = SplitOperationMetadata::find(&normalization.directives) @@ -196,7 +196,7 @@ pub fn generate_artifacts( _ => vec![], } ) - .collect(); + .collect() } fn generate_normalization_artifact( @@ -309,7 +309,7 @@ struct OperationGroup<'a> { typegen: Option<&'a Arc>, } -impl<'a> OperationGroup<'a> { +impl OperationGroup<'_> { fn new() -> Self { OperationGroup { normalization: None, diff --git a/compiler/crates/relay-compiler/src/build_project/validate.rs b/compiler/crates/relay-compiler/src/build_project/validate.rs index 660106ecfa560..ef1ff25506d76 100644 --- a/compiler/crates/relay-compiler/src/build_project/validate.rs +++ b/compiler/crates/relay-compiler/src/build_project/validate.rs @@ -15,9 +15,11 @@ use graphql_ir::Program; use relay_config::ProjectConfig; use relay_transforms::disallow_circular_no_inline_fragments; use relay_transforms::disallow_readtime_features_in_mutations; +use relay_transforms::disallow_required_on_non_null_field; use relay_transforms::disallow_reserved_aliases; use relay_transforms::disallow_typename_on_root; use relay_transforms::validate_assignable_directive; +use relay_transforms::validate_client_schema_extensions_use_catch; use relay_transforms::validate_connections; use relay_transforms::validate_fragment_alias_conflict; use relay_transforms::validate_global_variable_names; @@ -45,11 +47,16 @@ pub fn validate_reader( project_config: &ProjectConfig, additional_validations: &Option, ) -> DiagnosticsResult> { - let output = try_all(vec![if let Some(ref validate) = additional_validations { - validate(program, project_config) - } else { - Ok(()) - }]); + let output = try_all(vec![ + // This validation is in this list because it depends upon + // metadata added by the required_directive transform. + disallow_required_on_non_null_field(program), + if let Some(ref validate) = additional_validations { + validate(program, project_config) + } else { + Ok(()) + }, + ]); transform_errors(output, project_config) } @@ -70,6 +77,7 @@ pub fn validate( validate_relay_directives(program), validate_global_variable_names(program), validate_module_names(program), + validate_client_schema_extensions_use_catch(program), validate_no_inline_fragments_with_raw_response_type(program), disallow_typename_on_root(program), validate_static_args(program), diff --git a/compiler/crates/relay-compiler/src/compiler_state.rs b/compiler/crates/relay-compiler/src/compiler_state.rs index 15a72c435bdbd..ea38c86bce695 100644 --- a/compiler/crates/relay-compiler/src/compiler_state.rs +++ b/compiler/crates/relay-compiler/src/compiler_state.rs @@ -940,7 +940,7 @@ mod clock_json_string { } struct JSONStringVisitor; - impl<'de> Visitor<'de> for JSONStringVisitor { + impl Visitor<'_> for JSONStringVisitor { type Value = Option; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/compiler/crates/relay-compiler/src/config.rs b/compiler/crates/relay-compiler/src/config.rs index c295b5f254e30..ca68596ad7db4 100644 --- a/compiler/crates/relay-compiler/src/config.rs +++ b/compiler/crates/relay-compiler/src/config.rs @@ -615,6 +615,138 @@ impl Config { } } } + + /// Compute all root paths that we need to query. All files relevant to the + /// compiler should be in these directories. + pub fn get_all_roots(&self) -> Vec { + let source_roots = self.get_source_roots(); + let extra_sources_roots = self.get_generated_sources_roots(); + let output_roots = self.get_output_dir_paths(); + let extension_roots = self.get_extension_roots(); + let schema_file_roots = self.get_schema_file_roots(); + let schema_dir_roots = self.get_schema_dir_paths(); + + unify_roots( + source_roots + .into_iter() + .chain(extra_sources_roots) + .chain(output_roots) + .chain(extension_roots) + .chain(schema_file_roots) + .chain(schema_dir_roots) + .collect(), + ) + } + + /// Returns all root directories of JS source files for the config. + pub fn get_source_roots(&self) -> Vec { + self.sources.keys().cloned().collect() + } + + /// Returns all root directories of JS source files for the config. + pub fn get_generated_sources_roots(&self) -> Vec { + self.generated_sources.keys().cloned().collect() + } + + /// Returns all root directories of GraphQL schema extension files for the + /// config. + pub fn get_extension_roots(&self) -> Vec { + self.projects + .values() + .flat_map(|project_config| project_config.schema_extensions.iter().cloned()) + .collect() + } + + /// Returns all output and extra artifact output directories for the config. + pub fn get_output_dir_paths(&self) -> Vec { + let output_dirs = self + .projects + .values() + .filter_map(|project_config| project_config.output.clone()); + + let extra_artifact_output_dirs = self + .projects + .values() + .filter_map(|project_config| project_config.extra_artifacts_output.clone()); + + output_dirs.chain(extra_artifact_output_dirs).collect() + } + + /// Returns all paths that contain GraphQL schema files for the config. + pub fn get_schema_file_paths(&self) -> Vec { + self.projects + .values() + .filter_map(|project_config| match &project_config.schema_location { + SchemaLocation::File(schema_file) => Some(schema_file.clone()), + SchemaLocation::Directory(_) => None, + }) + .collect() + } + + /// Returns all GraphQL schema directories for the config. + pub fn get_schema_dir_paths(&self) -> Vec { + self.projects + .values() + .filter_map(|project_config| match &project_config.schema_location { + SchemaLocation::File(_) => None, + SchemaLocation::Directory(schema_dir) => Some(schema_dir.clone()), + }) + .collect() + } + + /// Returns root directories that contain GraphQL schema files. + pub fn get_schema_file_roots(&self) -> impl Iterator { + self.get_schema_file_paths().into_iter().map(|schema_path| { + schema_path + .parent() + .expect("A schema in the project root directory is currently not supported.") + .to_owned() + }) + } +} + +/// Finds the roots of a set of paths. This filters any paths +/// that are a subdirectory of other paths in the input. +fn unify_roots(mut paths: Vec) -> Vec { + paths.sort(); + let mut roots = Vec::new(); + for path in paths { + match roots.last() { + Some(prev) if path.starts_with(prev) => { + // skip + } + _ => { + roots.push(path); + } + } + } + roots +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_unify_roots() { + assert_eq!(unify_roots(vec![]).len(), 0); + assert_eq!( + unify_roots(vec!["Apps".into(), "Libraries".into()]), + &[PathBuf::from("Apps"), PathBuf::from("Libraries")] + ); + assert_eq!( + unify_roots(vec!["Apps".into(), "Apps/Foo".into()]), + &[PathBuf::from("Apps")] + ); + assert_eq!( + unify_roots(vec!["Apps/Foo".into(), "Apps".into()]), + &[PathBuf::from("Apps")] + ); + assert_eq!( + unify_roots(vec!["Foo".into(), "Foo2".into()]), + &[PathBuf::from("Foo"), PathBuf::from("Foo2"),] + ); + } } impl fmt::Debug for Config { @@ -872,12 +1004,12 @@ impl SingleProjectConfigFile { } })?, ); - for extension_dir in self.schema_extensions.iter() { + for extension_path in self.schema_extensions.iter() { paths.push( - canonicalize(root_dir.join(extension_dir.clone())).map_err(|_| { - ConfigValidationError::ExtensionDirNotExistent { + canonicalize(root_dir.join(extension_path.clone())).map_err(|_| { + ConfigValidationError::ExtensionPathNotExistent { project_name: self.project_name, - extension_dir: extension_dir.clone(), + extension_path: extension_path.clone(), } })?, ); diff --git a/compiler/crates/relay-compiler/src/errors.rs b/compiler/crates/relay-compiler/src/errors.rs index 0f45dcb71ba1b..4c2bc417fae8a 100644 --- a/compiler/crates/relay-compiler/src/errors.rs +++ b/compiler/crates/relay-compiler/src/errors.rs @@ -218,11 +218,11 @@ pub enum ConfigValidationError { }, #[error( - "The `schemaExtensions` configured for project `{project_name}` does not exist at `{extension_dir}`." + "The `schemaExtensions` configured for project `{project_name}` does not exist at `{extension_path}`." )] - ExtensionDirNotExistent { + ExtensionPathNotExistent { project_name: ProjectName, - extension_dir: PathBuf, + extension_path: PathBuf, }, #[error( diff --git a/compiler/crates/relay-compiler/src/file_source/walk_dir_file_source.rs b/compiler/crates/relay-compiler/src/file_source/walk_dir_file_source.rs index 6a1280b10ecfb..4b78bebb2d38b 100644 --- a/compiler/crates/relay-compiler/src/file_source/walk_dir_file_source.rs +++ b/compiler/crates/relay-compiler/src/file_source/walk_dir_file_source.rs @@ -80,8 +80,11 @@ impl WalkDirFileSource { } fn find_files(&self) -> Vec { - WalkDir::new(self.config.root_dir.clone()) - .into_iter() + self.config + .get_all_roots() + .iter() + .map(|source| self.config.root_dir.join(source)) + .flat_map(WalkDir::new) .filter_map(|entry| { let dir_entry = entry.ok()?; let relative_path = dir_entry diff --git a/compiler/crates/relay-compiler/src/file_source/watchman_file_source.rs b/compiler/crates/relay-compiler/src/file_source/watchman_file_source.rs index 9bb046b549f06..0797c14470bc9 100644 --- a/compiler/crates/relay-compiler/src/file_source/watchman_file_source.rs +++ b/compiler/crates/relay-compiler/src/file_source/watchman_file_source.rs @@ -20,7 +20,6 @@ use relay_saved_state_loader::SavedStateLoader; pub use watchman_client::prelude::Clock; use watchman_client::prelude::*; -use super::watchman_query_builder::get_all_roots; use super::watchman_query_builder::get_watchman_expr; use super::FileSourceResult; use crate::compiler_state::CompilerState; @@ -345,7 +344,8 @@ async fn query_file_result( ..Default::default() } } else { - let query_roots = get_all_roots(config) + let query_roots = config + .get_all_roots() .into_iter() .map(PathGeneratorElement::RecursivePath) .collect(); diff --git a/compiler/crates/relay-compiler/src/file_source/watchman_query_builder.rs b/compiler/crates/relay-compiler/src/file_source/watchman_query_builder.rs index ef34780cb284a..d74db913aaa8b 100644 --- a/compiler/crates/relay-compiler/src/file_source/watchman_query_builder.rs +++ b/compiler/crates/relay-compiler/src/file_source/watchman_query_builder.rs @@ -14,7 +14,6 @@ use watchman_client::prelude::*; use crate::compiler_state::ProjectSet; use crate::config::Config; -use crate::config::SchemaLocation; type FnvIndexMap = IndexMap; @@ -45,30 +44,30 @@ pub fn get_watchman_expr(config: &Config) -> Expr { expressions.push(expr_any(generated_sources_dir_exprs)); } - let output_dir_paths = get_output_dir_paths(config); + let output_dir_paths = config.get_output_dir_paths(); if !output_dir_paths.is_empty() { let output_dir_expr = expr_files_in_dirs(output_dir_paths); expressions.push(output_dir_expr); } - let schema_file_paths = get_schema_file_paths(config); + let schema_file_paths = config.get_schema_file_paths(); if !schema_file_paths.is_empty() { let schema_file_expr = Expr::Name(NameTerm { - paths: get_schema_file_paths(config), + paths: config.get_schema_file_paths(), wholename: true, }); expressions.push(schema_file_expr); } - let schema_dir_paths = get_schema_dir_paths(config); + let schema_dir_paths = config.get_schema_dir_paths(); if !schema_dir_paths.is_empty() { let schema_dir_expr = expr_graphql_files_in_dirs(schema_dir_paths); expressions.push(schema_dir_expr); } - let extension_roots = get_extension_roots(config); + let extension_roots = config.get_extension_roots(); if !extension_roots.is_empty() { - let extensions_expr = expr_graphql_files_in_dirs(extension_roots); + let extensions_expr = expr_graphql_file_or_dir_contents(extension_roots); expressions.push(extensions_expr); } @@ -123,98 +122,6 @@ fn get_project_file_ext_expr(typegen_language: TypegenLanguage) -> Expr { }) } -/// Compute all root paths that we need to query Watchman with. All files -/// relevant to the compiler should be in these directories. -pub fn get_all_roots(config: &Config) -> Vec { - let source_roots = get_source_roots(config); - let extra_sources_roots = get_generated_sources_roots(config); - let output_roots = get_output_dir_paths(config); - let extension_roots = get_extension_roots(config); - let schema_file_roots = get_schema_file_roots(config); - let schema_dir_roots = get_schema_dir_paths(config); - unify_roots( - source_roots - .into_iter() - .chain(extra_sources_roots) - .chain(output_roots) - .chain(extension_roots) - .chain(schema_file_roots) - .chain(schema_dir_roots) - .collect(), - ) -} - -/// Returns all root directories of JS source files for the config. -fn get_source_roots(config: &Config) -> Vec { - config.sources.keys().cloned().collect() -} - -/// Returns all root directories of JS source files for the config. -fn get_generated_sources_roots(config: &Config) -> Vec { - config.generated_sources.keys().cloned().collect() -} - -/// Returns all root directories of GraphQL schema extension files for the -/// config. -fn get_extension_roots(config: &Config) -> Vec { - config - .projects - .values() - .flat_map(|project_config| project_config.schema_extensions.iter().cloned()) - .collect() -} - -/// Returns all output and extra artifact output directories for the config. -fn get_output_dir_paths(config: &Config) -> Vec { - let output_dirs = config - .projects - .values() - .filter_map(|project_config| project_config.output.clone()); - - let extra_artifact_output_dirs = config - .projects - .values() - .filter_map(|project_config| project_config.extra_artifacts_output.clone()); - - output_dirs.chain(extra_artifact_output_dirs).collect() -} - -/// Returns all paths that contain GraphQL schema files for the config. -fn get_schema_file_paths(config: &Config) -> Vec { - config - .projects - .values() - .filter_map(|project_config| match &project_config.schema_location { - SchemaLocation::File(schema_file) => Some(schema_file.clone()), - SchemaLocation::Directory(_) => None, - }) - .collect() -} - -/// Returns all GraphQL schema directories for the config. -fn get_schema_dir_paths(config: &Config) -> Vec { - config - .projects - .values() - .filter_map(|project_config| match &project_config.schema_location { - SchemaLocation::File(_) => None, - SchemaLocation::Directory(schema_dir) => Some(schema_dir.clone()), - }) - .collect() -} - -/// Returns root directories that contain GraphQL schema files. -fn get_schema_file_roots(config: &Config) -> impl Iterator { - get_schema_file_paths(config) - .into_iter() - .map(|schema_path| { - schema_path - .parent() - .expect("A schema in the project root directory is currently not supported.") - .to_owned() - }) -} - fn expr_files_in_dirs(roots: Vec) -> Expr { expr_any( roots @@ -226,13 +133,27 @@ fn expr_files_in_dirs(roots: Vec) -> Expr { fn expr_graphql_files_in_dirs(roots: Vec) -> Expr { Expr::All(vec![ - // ending in *.graphql + // ending in *.graphql or *.gql Expr::Suffix(vec!["graphql".into(), "gql".into()]), // in one of the extension directories expr_files_in_dirs(roots), ]) } +// Expression to get all graphql items by path or path of containing folder. +fn expr_graphql_file_or_dir_contents(paths: Vec) -> Expr { + Expr::All(vec![ + Expr::Suffix(vec!["graphql".into(), "gql".into()]), + Expr::Any(vec![ + Expr::Name(NameTerm { + paths: paths.clone(), + wholename: true, + }), + expr_files_in_dirs(paths), + ]), + ]) +} + /// Helper to create an `anyof` expression if multiple items are passed or just /// return the expression for a single item input `Vec`. /// Panics for empty expressions. These are not valid in Watchman. We could @@ -245,47 +166,3 @@ fn expr_any(expressions: Vec) -> Expr { _ => Expr::Any(expressions), } } - -/// Finds the roots of a set of paths. This filters any paths -/// that are a subdirectory of other paths in the input. -fn unify_roots(mut paths: Vec) -> Vec { - paths.sort(); - let mut roots = Vec::new(); - for path in paths { - match roots.last() { - Some(prev) if path.starts_with(prev) => { - // skip - } - _ => { - roots.push(path); - } - } - } - roots -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_unify_roots() { - assert_eq!(unify_roots(vec![]).len(), 0); - assert_eq!( - unify_roots(vec!["Apps".into(), "Libraries".into()]), - &[PathBuf::from("Apps"), PathBuf::from("Libraries")] - ); - assert_eq!( - unify_roots(vec!["Apps".into(), "Apps/Foo".into()]), - &[PathBuf::from("Apps")] - ); - assert_eq!( - unify_roots(vec!["Apps/Foo".into(), "Apps".into()]), - &[PathBuf::from("Apps")] - ); - assert_eq!( - unify_roots(vec!["Foo".into(), "Foo2".into()]), - &[PathBuf::from("Foo"), PathBuf::from("Foo2"),] - ); - } -} diff --git a/compiler/crates/relay-compiler/src/get_programs.rs b/compiler/crates/relay-compiler/src/get_programs.rs index dc5d0a7d4e50c..07bdbbf16b470 100644 --- a/compiler/crates/relay-compiler/src/get_programs.rs +++ b/compiler/crates/relay-compiler/src/get_programs.rs @@ -5,10 +5,12 @@ * LICENSE file in the root directory of this source tree. */ +use std::collections::HashMap; use std::sync::Arc; use std::sync::Mutex; use common::PerfLogger; +use relay_config::ProjectName; use relay_transforms::Programs; use crate::compiler::Compiler; @@ -24,19 +26,24 @@ use crate::NoopArtifactWriter; pub async fn get_programs( mut config: Config, perf_logger: Arc, -) -> (Vec>, CompilerState, Arc) { - let raw_programs: Arc>>> = Arc::new(Mutex::new(vec![])); +) -> ( + HashMap>, + CompilerState, + Arc, +) { + let raw_programs: Arc>>> = + Arc::new(Mutex::new(HashMap::new())); let raw_programs_cloned = raw_programs.clone(); config.compile_everything = true; config.generate_virtual_id_file_name = None; config.artifact_writer = Box::new(NoopArtifactWriter); config.generate_extra_artifacts = Some(Box::new( - move |_config, _project_config, _schema, programs, _artifacts| { + move |_config, project_config, _schema, programs, _artifacts| { raw_programs_cloned .lock() .unwrap() - .push(Arc::new(programs.clone())); + .insert(project_config.name, Arc::new(programs.clone())); vec![] }, )); diff --git a/compiler/crates/relay-compiler/src/status_reporter.rs b/compiler/crates/relay-compiler/src/status_reporter.rs index 1970db1da02ba..2e0273c1809ed 100644 --- a/compiler/crates/relay-compiler/src/status_reporter.rs +++ b/compiler/crates/relay-compiler/src/status_reporter.rs @@ -78,6 +78,9 @@ impl ConsoleStatusReporter { match severity { DiagnosticSeverity::ERROR => error!("{}", output), DiagnosticSeverity::WARNING => warn!("{}", output), + DiagnosticSeverity::HINT => { + // Opting to omit, not emit, hints in the CLI output. + } _ => info!("{}", output), } } diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/client-3D-resolvers-enabled-client-3D-fragment.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/client-3D-resolvers-enabled-client-3D-fragment.expected index 10b36c368c75b..9938518815f29 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/client-3D-resolvers-enabled-client-3D-fragment.expected +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/client-3D-resolvers-enabled-client-3D-fragment.expected @@ -56,6 +56,60 @@ type SpecialUser implements BasicUser @__RelayResolverModel { "language": "flow" } ==================================== OUTPUT =================================== +{ + "kind": "SplitOperation", + "metadata": {}, + "name": "client3DResolversEnabledClient3DFragment_ClientUserFragment$normalization", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "data", + "storageKey": null + } + ] + } + ] +} + +{ + "kind": "SplitOperation", + "metadata": {}, + "name": "client3DResolversEnabledClient3DFragment_SpecialUserFragment$normalization", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "data", + "storageKey": null + } + ] + } + ] +} + import JSResource from 'JSResource'; { "fragment": { @@ -174,6 +228,15 @@ import JSResource from 'JSResource'; { "kind": "InlineFragment", "selections": [ + { + "args": null, + "documentName": "client3DResolversEnabledClient3DFragment_clientSideQuery", + "fragmentName": "client3DResolversEnabledClient3DFragment_ClientUserFragment", + "fragmentPropName": "ClientUserFragment", + "kind": "ModuleImport", + "componentModuleProvider": () => JSResource('m#ClientUser.react'), + "operationModuleProvider": () => JSResource('m#client3DResolversEnabledClient3DFragment_ClientUserFragment$normalization.graphql') + }, { "alias": null, "args": null, @@ -188,6 +251,15 @@ import JSResource from 'JSResource'; { "kind": "InlineFragment", "selections": [ + { + "args": null, + "documentName": "client3DResolversEnabledClient3DFragment_clientSideQuery", + "fragmentName": "client3DResolversEnabledClient3DFragment_SpecialUserFragment", + "fragmentPropName": "SpecialUserFragment", + "kind": "ModuleImport", + "componentModuleProvider": () => JSResource('m#SpecialUser.react'), + "operationModuleProvider": () => JSResource('m#client3DResolversEnabledClient3DFragment_SpecialUserFragment$normalization.graphql') + }, { "alias": null, "args": null, diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/fragment-on-non-node-fetchable-type.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/fragment-on-non-node-fetchable-type.expected index 94c3498c75c31..9b1407df008bc 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/fragment-on-non-node-fetchable-type.expected +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/fragment-on-non-node-fetchable-type.expected @@ -150,13 +150,6 @@ fragment fragmentOnNonNodeFetchableType_ProfilePicture on User { "name": "fetch_id", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null - }, { "alias": null, "args": null, @@ -204,7 +197,6 @@ fragment fragmentOnNonNodeFetchableType_RefetchableFragment on NonNodeStory { id } fetch_id - __token } @@ -293,13 +285,6 @@ fragment fragmentOnNonNodeFetchableType_RefetchableFragment on NonNodeStory { "kind": "ScalarField", "name": "fetch_id", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null } ], "type": "NonNodeStory", diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.expected new file mode 100644 index 0000000000000..2cb3d0efa4b9b --- /dev/null +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.expected @@ -0,0 +1,45 @@ +==================================== INPUT ==================================== +# expected-to-throw + +query prefetchablePaginationQueryWithConflictingArgsQuery($site: String) { + node(id: "x") { + ...prefetchablePaginationQueryWithConflictingArgs_FirstFragment @arguments(site: $site) + } +} + +fragment prefetchablePaginationQueryWithConflictingArgs_FirstFragment on Node + @refetchable(queryName: "RefetchableFragmentQuery") + @argumentDefinitions( + count: {type: "Int", defaultValue: 10} + cursor: {type: "ID"} + site: {type: "String"} + ) { + id + ...prefetchablePaginationQueryWithConflictingArgs_SecondFragment + ... on User { + name + friends(after: $cursor, first: $count) + @connection(key: "PaginationFragment_friends", prefetchable_pagination: true) { + edges { + node { + id + # local $site + url(site: $site) + } + } + } + } +} + +fragment prefetchablePaginationQueryWithConflictingArgs_SecondFragment on Node { + # global $site + p2: url(site: $site) +} +==================================== ERROR ==================================== +✖︎ Fragment variable `$site` conflicts with a global variable generated by the @refetchable generated query + + prefetchable-pagination-query-with-conflicting-args.invalid.graphql:14:5 + 13 │ cursor: {type: "ID"} + 14 │ site: {type: "String"} + │ ^^^^ + 15 │ ) { diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.graphql b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.graphql new file mode 100644 index 0000000000000..c16cbd882625e --- /dev/null +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.graphql @@ -0,0 +1,36 @@ +# expected-to-throw + +query prefetchablePaginationQueryWithConflictingArgsQuery($site: String) { + node(id: "x") { + ...prefetchablePaginationQueryWithConflictingArgs_FirstFragment @arguments(site: $site) + } +} + +fragment prefetchablePaginationQueryWithConflictingArgs_FirstFragment on Node + @refetchable(queryName: "RefetchableFragmentQuery") + @argumentDefinitions( + count: {type: "Int", defaultValue: 10} + cursor: {type: "ID"} + site: {type: "String"} + ) { + id + ...prefetchablePaginationQueryWithConflictingArgs_SecondFragment + ... on User { + name + friends(after: $cursor, first: $count) + @connection(key: "PaginationFragment_friends", prefetchable_pagination: true) { + edges { + node { + id + # local $site + url(site: $site) + } + } + } + } +} + +fragment prefetchablePaginationQueryWithConflictingArgs_SecondFragment on Node { + # global $site + p2: url(site: $site) +} diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.expected new file mode 100644 index 0000000000000..4c550f610761a --- /dev/null +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.expected @@ -0,0 +1,1125 @@ +==================================== INPUT ==================================== +query prefetchablePaginationQueryWithoutConflictingArgsQuery($site: String) { + node(id: "x") { + ...prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment @arguments(site: $site) + ...prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment @arguments(site: $site) + } +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment on Page + @refetchable(queryName: "RefetchableFragmentQuery") + @argumentDefinitions( + count: {type: "Int", defaultValue: 10} + cursor: {type: "ID"} + site: {type: "String"} + ) { + name + friends(after: $cursor, first: $count) + @connection(key: "PaginationFragment_friends", prefetchable_pagination: true) { + edges { + node { + id + url(site: $site) + } + } + } +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment on User + @argumentDefinitions( + count: {type: "Int", defaultValue: 10} + cursor: {type: "ID"} + site: {type: "String"} + ) { + id + friends(after: $cursor, first: $count) + @connection(key: "PaginationFragment2_friends") { + edges { + node { + id + url(site: $site) + } + } + } +} +==================================== OUTPUT =================================== +{ + "fragment": { + "argumentDefinitions": [ + { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "count" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "cursor" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "site" + } + ], + "kind": "Fragment", + "metadata": null, + "name": "RefetchableFragmentQuery", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": [ + { + "kind": "Variable", + "name": "count", + "variableName": "count" + }, + { + "kind": "Variable", + "name": "cursor", + "variableName": "cursor" + }, + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "FragmentSpread", + "name": "prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "count" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "cursor" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "site" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } + ], + "kind": "Operation", + "name": "RefetchableFragmentQuery", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "after", + "variableName": "cursor" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "count" + } + ], + "concreteType": "FriendsConnection", + "kind": "LinkedField", + "name": "friends", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "FriendsEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "ScalarField", + "name": "url", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "after", + "variableName": "cursor" + }, + { + "kind": "Variable", + "name": "first", + "variableName": "count" + } + ], + "filters": null, + "handle": "connection", + "key": "PaginationFragment_friends", + "kind": "LinkedHandle", + "name": "friends" + } + ], + "type": "Page", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "31dcd57f42128b8d975e6224202a17c9", + "id": null, + "metadata": {}, + "name": "RefetchableFragmentQuery", + "operationKind": "query", + "text": null + } +} + +QUERY: + +query RefetchableFragmentQuery( + $count: Int = 10 + $cursor: ID + $site: String + $id: ID! +) { + node(id: $id) { + __typename + ...prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment_1Xo9Zp + id + } +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment_1Xo9Zp on Page { + name + friends(after: $cursor, first: $count) { + edges { + ...prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment__edges_1Xo9Zp + } + pageInfo { + endCursor + hasNextPage + } + } + id +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment__edges_1Xo9Zp on FriendsEdge { + node { + id + url(site: $site) + __typename + } + cursor +} + + +{ + "fragment": { + "argumentDefinitions": [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "site" + } + ], + "kind": "Fragment", + "metadata": null, + "name": "prefetchablePaginationQueryWithoutConflictingArgsQuery", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "id", + "value": "x" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": [ + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "FragmentSpread", + "name": "prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment" + }, + { + "args": [ + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "FragmentSpread", + "name": "prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment" + } + ], + "storageKey": "node(id:\"x\")" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "site" + } + ], + "kind": "Operation", + "name": "prefetchablePaginationQueryWithoutConflictingArgsQuery", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "id", + "value": "x" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 10 + } + ], + "concreteType": "FriendsConnection", + "kind": "LinkedField", + "name": "friends", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "FriendsEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "ScalarField", + "name": "url", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "friends(first:10)" + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 10 + } + ], + "filters": null, + "handle": "connection", + "key": "PaginationFragment_friends", + "kind": "LinkedHandle", + "name": "friends" + } + ], + "type": "Page", + "abstractKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 10 + } + ], + "concreteType": "FriendsConnection", + "kind": "LinkedField", + "name": "friends", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "FriendsEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "ScalarField", + "name": "url", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "friends(first:10)" + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 10 + } + ], + "filters": null, + "handle": "connection", + "key": "PaginationFragment2_friends", + "kind": "LinkedHandle", + "name": "friends" + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": "node(id:\"x\")" + } + ] + }, + "params": { + "cacheID": "61508c3bf1b78d9d4b7d6609870e28da", + "id": null, + "metadata": {}, + "name": "prefetchablePaginationQueryWithoutConflictingArgsQuery", + "operationKind": "query", + "text": null + } +} + +QUERY: + +query prefetchablePaginationQueryWithoutConflictingArgsQuery( + $site: String +) { + node(id: "x") { + __typename + ...prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment_QaI6y + ...prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment_QaI6y + id + } +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment_QaI6y on Page { + name + friends(first: 10) { + edges { + ...prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment__edges_2VKHkd + } + pageInfo { + endCursor + hasNextPage + } + } + id +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment__edges_2VKHkd on FriendsEdge { + node { + id + url(site: $site) + __typename + } + cursor +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment_QaI6y on User { + id + friends(first: 10) { + edges { + node { + id + url(site: $site) + __typename + } + cursor + } + pageInfo { + endCursor + hasNextPage + } + } +} + + +{ + "argumentDefinitions": [ + { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "count" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "cursor" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "site" + } + ], + "kind": "Fragment", + "metadata": { + "connection": [ + { + "count": "count", + "cursor": "cursor", + "direction": "forward", + "path": [ + "friends" + ] + } + ], + "refetch": { + "connection": { + "forward": { + "count": "count", + "cursor": "cursor" + }, + "backward": null, + "path": [ + "friends" + ] + }, + "fragmentPathInResult": [ + "node" + ], + "operation": require('RefetchableFragmentQuery.graphql'), + "identifierInfo": { + "identifierField": "id", + "identifierQueryVariableName": "id" + }, + "edgesFragment": require('prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment__edges.graphql') + } + }, + "name": "prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": "friends", + "args": null, + "concreteType": "FriendsConnection", + "kind": "LinkedField", + "name": "__PaginationFragment_friends_connection", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "FriendsEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "args": [ + { + "kind": "Variable", + "name": "count", + "variableName": "count" + }, + { + "kind": "Variable", + "name": "cursor", + "variableName": "cursor" + }, + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "FragmentSpread", + "name": "prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment__edges" + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "type": "Page", + "abstractKey": null +} + +{ + "argumentDefinitions": [ + { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "count" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "cursor" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "site" + } + ], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment__edges", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "ScalarField", + "name": "url", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "type": "FriendsEdge", + "abstractKey": null +} + +{ + "argumentDefinitions": [ + { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "count" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "cursor" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "site" + } + ], + "kind": "Fragment", + "metadata": { + "connection": [ + { + "count": "count", + "cursor": "cursor", + "direction": "forward", + "path": [ + "friends" + ] + } + ] + }, + "name": "prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": "friends", + "args": null, + "concreteType": "FriendsConnection", + "kind": "LinkedField", + "name": "__PaginationFragment2_friends_connection", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "FriendsEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "site", + "variableName": "site" + } + ], + "kind": "ScalarField", + "name": "url", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +} diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.graphql b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.graphql new file mode 100644 index 0000000000000..cab3ddda2e68c --- /dev/null +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.graphql @@ -0,0 +1,43 @@ +query prefetchablePaginationQueryWithoutConflictingArgsQuery($site: String) { + node(id: "x") { + ...prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment @arguments(site: $site) + ...prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment @arguments(site: $site) + } +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_FirstFragment on Page + @refetchable(queryName: "RefetchableFragmentQuery") + @argumentDefinitions( + count: {type: "Int", defaultValue: 10} + cursor: {type: "ID"} + site: {type: "String"} + ) { + name + friends(after: $cursor, first: $count) + @connection(key: "PaginationFragment_friends", prefetchable_pagination: true) { + edges { + node { + id + url(site: $site) + } + } + } +} + +fragment prefetchablePaginationQueryWithoutConflictingArgs_SecondFragment on User + @argumentDefinitions( + count: {type: "Int", defaultValue: 10} + cursor: {type: "ID"} + site: {type: "String"} + ) { + id + friends(after: $cursor, first: $count) + @connection(key: "PaginationFragment2_friends") { + edges { + node { + id + url(site: $site) + } + } + } +} diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-refetchable-fragment-with-connection.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-refetchable-fragment-with-connection.expected index eaa1126e760cb..8de231abb0395 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-refetchable-fragment-with-connection.expected +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/prefetchable-refetchable-fragment-with-connection.expected @@ -293,7 +293,7 @@ fragment prefetchableRefetchableFragmentWithConnection_PaginationFragment_1G22uz name friends(after: $cursor, first: $count) { edges { - ...prefetchableRefetchableFragmentWithConnection_PaginationFragment__edges + ...prefetchableRefetchableFragmentWithConnection_PaginationFragment__edges_1G22uz } pageInfo { endCursor @@ -303,7 +303,7 @@ fragment prefetchableRefetchableFragmentWithConnection_PaginationFragment_1G22uz } } -fragment prefetchableRefetchableFragmentWithConnection_PaginationFragment__edges on FriendsEdge { +fragment prefetchableRefetchableFragmentWithConnection_PaginationFragment__edges_1G22uz on FriendsEdge { node { id __typename @@ -395,7 +395,18 @@ fragment prefetchableRefetchableFragmentWithConnection_PaginationFragment__edges "plural": true, "selections": [ { - "args": null, + "args": [ + { + "kind": "Variable", + "name": "count", + "variableName": "count" + }, + { + "kind": "Variable", + "name": "cursor", + "variableName": "cursor" + } + ], "kind": "FragmentSpread", "name": "prefetchableRefetchableFragmentWithConnection_PaginationFragment__edges" } @@ -440,7 +451,18 @@ fragment prefetchableRefetchableFragmentWithConnection_PaginationFragment__edges } { - "argumentDefinitions": [], + "argumentDefinitions": [ + { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "count" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "cursor" + } + ], "kind": "Fragment", "metadata": { "plural": true diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable-arg.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable-arg.expected index 4e8fe2c933413..120dd981e118d 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable-arg.expected +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable-arg.expected @@ -82,13 +82,6 @@ fragment refetchableFragmentOnNodeAndFetchableArg_RefetchableFragment on Fetchab "kind": "ScalarField", "name": "fetch_id", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null } ], "storageKey": null @@ -119,7 +112,6 @@ query RefetchableFragmentQuery( fragment refetchableFragmentOnNodeAndFetchableArg_RefetchableFragment on FetchableType { id fetch_id - __token } @@ -154,13 +146,6 @@ fragment refetchableFragmentOnNodeAndFetchableArg_RefetchableFragment on Fetchab "kind": "ScalarField", "name": "fetch_id", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null } ], "type": "FetchableType", diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable.expected index 460c33e7373dc..6b06a9dd96626 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable.expected +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-fragment-on-node-and-fetchable.expected @@ -84,13 +84,6 @@ fragment refetchableFragmentOnNodeAndFetchable_RefetchableFragment on FetchableT "kind": "ScalarField", "name": "fetch_id", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null } ], "storageKey": null @@ -121,7 +114,6 @@ query RefetchableFragmentQuery( fragment refetchableFragmentOnNodeAndFetchable_RefetchableFragment on FetchableType { id fetch_id - __token } @@ -156,13 +148,6 @@ fragment refetchableFragmentOnNodeAndFetchable_RefetchableFragment on FetchableT "kind": "ScalarField", "name": "fetch_id", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null } ], "type": "FetchableType", diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.expected deleted file mode 100644 index 216e330f65e64..0000000000000 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.expected +++ /dev/null @@ -1,30 +0,0 @@ -==================================== INPUT ==================================== -# expected-to-throw - -query refetchableWithArgumentsQuery($site: String) { - node(id: "x") { - ...refetchableWithArgumentsF1 - } -} - -fragment refetchableWithArgumentsF1 on Node - @argumentDefinitions(site: {type: "String"}) - @refetchable(queryName: "RefetchableWithArgumentsRefetchQuery") -{ - # local $site - p1: url(site: $site) - ...refetchableWithArgumentsF2 -} - -fragment refetchableWithArgumentsF2 on Node { - # global $site - p2: url(site: $site) -} -==================================== ERROR ==================================== -✖︎ Fragment variable `$site` conflicts with a global variable generated by the @refetchable generated query - - refetchable-with-arguments.invalid.graphql:10:24 - 9 │ fragment refetchableWithArgumentsF1 on Node - 10 │ @argumentDefinitions(site: {type: "String"}) - │ ^^^^ - 11 │ @refetchable(queryName: "RefetchableWithArgumentsRefetchQuery") diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.graphql b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.graphql deleted file mode 100644 index 95a00bfe3171e..0000000000000 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.graphql +++ /dev/null @@ -1,21 +0,0 @@ -# expected-to-throw - -query refetchableWithArgumentsQuery($site: String) { - node(id: "x") { - ...refetchableWithArgumentsF1 - } -} - -fragment refetchableWithArgumentsF1 on Node - @argumentDefinitions(site: {type: "String"}) - @refetchable(queryName: "RefetchableWithArgumentsRefetchQuery") -{ - # local $site - p1: url(site: $site) - ...refetchableWithArgumentsF2 -} - -fragment refetchableWithArgumentsF2 on Node { - # global $site - p2: url(site: $site) -} diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.expected new file mode 100644 index 0000000000000..b53de0eb6ae2a --- /dev/null +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.expected @@ -0,0 +1,108 @@ +==================================== INPUT ==================================== +query updatableFragmentSpreadWithDangerouslyUnaliasedFixmeQuery { + me { + ...updatableFragmentSpreadWithDangerouslyUnaliasedFixme_user @dangerously_unaliased_fixme + } +} + +fragment updatableFragmentSpreadWithDangerouslyUnaliasedFixme_user on User @updatable { + firstName +} +==================================== OUTPUT =================================== +{ + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "updatableFragmentSpreadWithDangerouslyUnaliasedFixmeQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "updatableFragmentSpreadWithDangerouslyUnaliasedFixme_user" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "updatableFragmentSpreadWithDangerouslyUnaliasedFixmeQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "9c1625f473e47737ba5ee76d36681bd4", + "id": null, + "metadata": {}, + "name": "updatableFragmentSpreadWithDangerouslyUnaliasedFixmeQuery", + "operationKind": "query", + "text": null + } +} + +QUERY: + +query updatableFragmentSpreadWithDangerouslyUnaliasedFixmeQuery { + me { + __typename + id + } +} + + +{ + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "updatableFragmentSpreadWithDangerouslyUnaliasedFixme_user", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "firstName", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +} diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.graphql b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.graphql new file mode 100644 index 0000000000000..19dc838b70fdc --- /dev/null +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.graphql @@ -0,0 +1,9 @@ +query updatableFragmentSpreadWithDangerouslyUnaliasedFixmeQuery { + me { + ...updatableFragmentSpreadWithDangerouslyUnaliasedFixme_user @dangerously_unaliased_fixme + } +} + +fragment updatableFragmentSpreadWithDangerouslyUnaliasedFixme_user on User @updatable { + firstName +} diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-defer.invalid.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-defer.invalid.expected index 3809713de3858..2e855edc9ee08 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-defer.invalid.expected +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/updatable-fragment-spread-with-defer.invalid.expected @@ -12,8 +12,8 @@ fragment updatableFragmentSpreadWithDefer_user on User @updatable { ==================================== ERROR ==================================== ✖︎ Directives are not allowed on spreads of updatable fragments. - updatable-fragment-spread-with-defer.invalid.graphql:4:8 + updatable-fragment-spread-with-defer.invalid.graphql:4:46 3 │ me { 4 │ ...updatableFragmentSpreadWithDefer_user @defer - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ ^^^^^^ 5 │ } diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts_test.rs b/compiler/crates/relay-compiler/tests/compile_relay_artifacts_test.rs index e5b2bfea3f8aa..922329204f1f6 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts_test.rs +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<220a462d1e8062621d9ac165e8d6b30d>> + * @generated SignedSource<<8e6457abd85bfe2e23fd93ec4d3a3cc2>> */ mod compile_relay_artifacts; @@ -992,6 +992,20 @@ async fn plural_fragment() { test_fixture(transform_fixture, file!(), "plural-fragment.graphql", "compile_relay_artifacts/fixtures/plural-fragment.expected", input, expected).await; } +#[tokio::test] +async fn prefetchable_pagination_query_with_conflicting_args_invalid() { + let input = include_str!("compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.graphql"); + let expected = include_str!("compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.expected"); + test_fixture(transform_fixture, file!(), "prefetchable-pagination-query-with-conflicting-args.invalid.graphql", "compile_relay_artifacts/fixtures/prefetchable-pagination-query-with-conflicting-args.invalid.expected", input, expected).await; +} + +#[tokio::test] +async fn prefetchable_pagination_query_without_conflicting_args() { + let input = include_str!("compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.graphql"); + let expected = include_str!("compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.expected"); + test_fixture(transform_fixture, file!(), "prefetchable-pagination-query-without-conflicting-args.graphql", "compile_relay_artifacts/fixtures/prefetchable-pagination-query-without-conflicting-args.expected", input, expected).await; +} + #[tokio::test] async fn prefetchable_refetchable_fragment_with_connection() { let input = include_str!("compile_relay_artifacts/fixtures/prefetchable-refetchable-fragment-with-connection.graphql"); @@ -1286,13 +1300,6 @@ async fn refetchable_with_arguments_conflicting_invalid() { test_fixture(transform_fixture, file!(), "refetchable-with-arguments-conflicting.invalid.graphql", "compile_relay_artifacts/fixtures/refetchable-with-arguments-conflicting.invalid.expected", input, expected).await; } -#[tokio::test] -async fn refetchable_with_arguments_invalid() { - let input = include_str!("compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.graphql"); - let expected = include_str!("compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.expected"); - test_fixture(transform_fixture, file!(), "refetchable-with-arguments.invalid.graphql", "compile_relay_artifacts/fixtures/refetchable-with-arguments.invalid.expected", input, expected).await; -} - #[tokio::test] async fn relay_client_id_field() { let input = include_str!("compile_relay_artifacts/fixtures/relay-client-id-field.graphql"); @@ -2042,6 +2049,13 @@ async fn updatable_fragment_spread() { test_fixture(transform_fixture, file!(), "updatable-fragment-spread.graphql", "compile_relay_artifacts/fixtures/updatable-fragment-spread.expected", input, expected).await; } +#[tokio::test] +async fn updatable_fragment_spread_with_dangerously_unaliased_fixme() { + let input = include_str!("compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.graphql"); + let expected = include_str!("compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.expected"); + test_fixture(transform_fixture, file!(), "updatable-fragment-spread-with-dangerously-unaliased-fixme.graphql", "compile_relay_artifacts/fixtures/updatable-fragment-spread-with-dangerously-unaliased-fixme.expected", input, expected).await; +} + #[tokio::test] async fn updatable_fragment_spread_with_defer_invalid() { let input = include_str!("compile_relay_artifacts/fixtures/updatable-fragment-spread-with-defer.invalid.graphql"); diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.expected b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.expected new file mode 100644 index 0000000000000..82b314391ac04 --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.expected @@ -0,0 +1,34 @@ +==================================== INPUT ==================================== +//- foo.js +graphql`query fooQuery @throwOnFieldError { + client_field +}` + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql", + "schemaExtensions": [ + "schema-extensions" + ] +} + +//- schema.graphql +type Query { + greeting: String +} + +//- schema-extensions/extension.graphql + +extend type Query { + client_field: String +} +==================================== OUTPUT =================================== +✖︎ Expected client-defined field within `@throwOnFieldError` to be annotated with `@catch`. Accessing an unset field is treated as a field error, but Relay cannot guarantee that client field will be set before they are read. Add `@catch` to explicitly handle the case where the field is unset. + + foo.js:2:3 + 1 │ query fooQuery @throwOnFieldError { + 2 │ client_field + │ ^^^^^^^^^^^^ + 3 │ } diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.input b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.input new file mode 100644 index 0000000000000..a279496d2b914 --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.input @@ -0,0 +1,25 @@ +//- foo.js +graphql`query fooQuery @throwOnFieldError { + client_field +}` + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql", + "schemaExtensions": [ + "schema-extensions" + ] +} + +//- schema.graphql +type Query { + greeting: String +} + +//- schema-extensions/extension.graphql + +extend type Query { + client_field: String +} diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.expected b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.expected new file mode 100644 index 0000000000000..6a9e39394beb5 --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.expected @@ -0,0 +1,292 @@ +==================================== INPUT ==================================== +//- foo.js +graphql`query fooQuery @throwOnFieldError { + # This does not need @catch because it is a resolver + clientUser { + # This does not need @catch because it was generated by + # a strong resolver + id + } +}` + +/** + * @RelayResolver ClientUser + * A strong type + */ + + /** + * @RelayResolver Query.clientUser: ClientUser + * Resolver that returns ClientUser + */ + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql", + "schemaExtensions": [ + "schema-extensions" + ] +} + +//- schema.graphql +type Query { + greeting: String +} + +//- schema-extensions/extension.graphql + +extend type Query { + client_field: String +} +==================================== OUTPUT =================================== +//- __generated__/ClientUser____relay_model_instance.graphql.js +/** + * SignedSource<<5a5913417956881a9f1ba2e4920fbd92>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { ClientUser__id$data } from "ClientUser__id.graphql"; +import type { FragmentType } from "relay-runtime"; +import {ClientUser as clientUserRelayModelInstanceResolverType} from "foo"; +// Type assertion validating that `clientUserRelayModelInstanceResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(clientUserRelayModelInstanceResolverType: ( + id: ClientUser__id$data['id'], +) => mixed); +declare export opaque type ClientUser____relay_model_instance$fragmentType: FragmentType; +export type ClientUser____relay_model_instance$data = {| + +__relay_model_instance: $NonMaybeType>, + +$fragmentType: ClientUser____relay_model_instance$fragmentType, +|}; +export type ClientUser____relay_model_instance$key = { + +$data?: ClientUser____relay_model_instance$data, + +$fragmentSpreads: ClientUser____relay_model_instance$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "ClientUser____relay_model_instance", + "selections": [ + { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "ClientUser__id" + }, + "kind": "RelayResolver", + "name": "__relay_model_instance", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('ClientUser__id.graphql'), require('foo').ClientUser, 'id', true), + "path": "__relay_model_instance" + } + ], + "type": "ClientUser", + "abstractKey": null +}; + +module.exports = ((node/*: any*/)/*: Fragment< + ClientUser____relay_model_instance$fragmentType, + ClientUser____relay_model_instance$data, +>*/); + +//- __generated__/ClientUser__id.graphql.js +/** + * SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type ClientUser__id$fragmentType: FragmentType; +export type ClientUser__id$data = {| + +id: string, + +$fragmentType: ClientUser__id$fragmentType, +|}; +export type ClientUser__id$key = { + +$data?: ClientUser__id$data, + +$fragmentSpreads: ClientUser__id$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "ClientUser__id", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ] + } + ], + "type": "ClientUser", + "abstractKey": null +}; + +module.exports = ((node/*: any*/)/*: Fragment< + ClientUser__id$fragmentType, + ClientUser__id$data, +>*/); + +//- __generated__/fooQuery.graphql.js +/** + * SignedSource<<224699c54aa3794c393a7f5145c8f9a5>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ClientRequest, ClientQuery } from 'relay-runtime'; +import type { DataID } from "relay-runtime"; +import {clientUser as queryClientUserResolverType} from "foo"; +// Type assertion validating that `queryClientUserResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryClientUserResolverType: () => ?{| + +id: DataID, +|}); +export type fooQuery$variables = {||}; +export type fooQuery$data = {| + +clientUser: ?{| + +id: string, + |}, +|}; +export type fooQuery = {| + response: fooQuery$data, + variables: fooQuery$variables, +|}; +*/ + +var node/*: ClientRequest*/ = (function(){ +var v0 = { + "alias": null, + "args": null, + "concreteType": "ClientUser", + "kind": "LinkedField", + "name": "clientUser", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "hasClientEdges": true, + "throwOnFieldError": true + }, + "name": "fooQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "concreteType": "ClientUser", + "modelResolvers": { + "ClientUser": { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "ClientUser__id" + }, + "kind": "RelayResolver", + "name": "clientUser", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('ClientUser__id.graphql'), require('foo').ClientUser, 'id', true), + "path": "clientUser.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayResolver", + "name": "clientUser", + "resolverModule": require('foo').clientUser, + "path": "clientUser" + }, + "linkedField": (v0/*: any*/) + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "fooQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "backingField": { + "name": "clientUser", + "args": null, + "fragment": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false + }, + "linkedField": (v0/*: any*/) + } + ] + }, + "params": { + "cacheID": "b4419e844fe6e6b6a0c48c1d2e9e7fc8", + "id": null, + "metadata": {}, + "name": "fooQuery", + "operationKind": "query", + "text": null + } +}; +})(); + +(node/*: any*/).hash = "a96f54d4f51f87ef55b7e2d6bc0c31be"; + +module.exports = ((node/*: any*/)/*: ClientQuery< + fooQuery$variables, + fooQuery$data, +>*/); diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.input b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.input new file mode 100644 index 0000000000000..3de2325be46a4 --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.input @@ -0,0 +1,40 @@ +//- foo.js +graphql`query fooQuery @throwOnFieldError { + # This does not need @catch because it is a resolver + clientUser { + # This does not need @catch because it was generated by + # a strong resolver + id + } +}` + +/** + * @RelayResolver ClientUser + * A strong type + */ + + /** + * @RelayResolver Query.clientUser: ClientUser + * Resolver that returns ClientUser + */ + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql", + "schemaExtensions": [ + "schema-extensions" + ] +} + +//- schema.graphql +type Query { + greeting: String +} + +//- schema-extensions/extension.graphql + +extend type Query { + client_field: String +} diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.expected b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.expected index dad4e6395ee4f..957ce1ecbe42f 100644 --- a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.expected +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.expected @@ -36,6 +36,9 @@ query ModuleNameQuery { "featureFlags": { "disable_deduping_common_structures_in_artifacts": { "kind": "enabled" + }, + "enforce_fragment_alias_where_ambiguous": { + "kind": "disabled" } } } diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.input b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.input index d589100d44364..cb3228688909f 100644 --- a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.input +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_before.input @@ -35,6 +35,9 @@ query ModuleNameQuery { "featureFlags": { "disable_deduping_common_structures_in_artifacts": { "kind": "enabled" + }, + "enforce_fragment_alias_where_ambiguous": { + "kind": "disabled" } } } diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.expected b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.expected new file mode 100644 index 0000000000000..fe16dfdc119e7 --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.expected @@ -0,0 +1,42 @@ +==================================== INPUT ==================================== +//- PersonComponent.js +graphql`query PersonComponentQuery { + plural_server @waterfall { + name + } +}` + +//- QueryResolvers.js +/** + * @RelayResolver Query.plural_server: [User] + */ + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql" +} + +//- schema.graphql +type Query { + greeting: String + node(id: ID!): Node +} + +interface Node { + id: ID! +} + +type User implements Node { + id: ID! + name: String +} +==================================== OUTPUT =================================== +✖︎ Unexpected Relay Resolver returning plual edge to type defined on the server. Relay Resolvers do not curretly support returning plural edges to server types. As a work around, consider defining a plural edge to a client type which has a singular edge to the server type. + + QueryResolvers.js:2:25 + 1 │ * + 2 │ * @RelayResolver Query.plural_server: [User] + │ ^^^^^^^^^^^^^ + 3 │ diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.input b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.input new file mode 100644 index 0000000000000..65199a9a5f064 --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.input @@ -0,0 +1,33 @@ +//- PersonComponent.js +graphql`query PersonComponentQuery { + plural_server @waterfall { + name + } +}` + +//- QueryResolvers.js +/** + * @RelayResolver Query.plural_server: [User] + */ + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql" +} + +//- schema.graphql +type Query { + greeting: String + node(id: ID!): Node +} + +interface Node { + id: ID! +} + +type User implements Node { + id: ID! + name: String +} diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs b/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs index db820da036835..f57352a16e06e 100644 --- a/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<44313b4ad0ca41fac58e6a820c78a157>> + * @generated SignedSource<<18ad721b702d974f6b034f393230738d>> */ mod relay_compiler_integration; @@ -47,6 +47,13 @@ async fn client_mutation_resolver_invalid_nonscalar() { test_fixture(transform_fixture, file!(), "client_mutation_resolver_invalid_nonscalar.input", "relay_compiler_integration/fixtures/client_mutation_resolver_invalid_nonscalar.expected", input, expected).await; } +#[tokio::test] +async fn client_schema_extension_in_throw_on_field_error() { + let input = include_str!("relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.input"); + let expected = include_str!("relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.expected"); + test_fixture(transform_fixture, file!(), "client_schema_extension_in_throw_on_field_error.input", "relay_compiler_integration/fixtures/client_schema_extension_in_throw_on_field_error.expected", input, expected).await; +} + #[tokio::test] async fn client_schema_extension_interface_uses_resolver_type() { let input = include_str!("relay_compiler_integration/fixtures/client_schema_extension_interface_uses_resolver_type.input"); @@ -145,6 +152,13 @@ async fn preloadable_query_typescript() { test_fixture(transform_fixture, file!(), "preloadable_query_typescript.input", "relay_compiler_integration/fixtures/preloadable_query_typescript.expected", input, expected).await; } +#[tokio::test] +async fn relay_resolvers_in_throw_on_field_error() { + let input = include_str!("relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.input"); + let expected = include_str!("relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.expected"); + test_fixture(transform_fixture, file!(), "relay_resolvers_in_throw_on_field_error.input", "relay_compiler_integration/fixtures/relay_resolvers_in_throw_on_field_error.expected", input, expected).await; +} + #[tokio::test] async fn repro_dangerously_unaliased_changes_output_after() { let input = include_str!("relay_compiler_integration/fixtures/repro_dangerously_unaliased_changes_output_after.input"); @@ -264,6 +278,13 @@ async fn resolver_returns_interface_of_live_and_non_live_strong_model_type() { test_fixture(transform_fixture, file!(), "resolver_returns_interface_of_live_and_non_live_strong_model_type.input", "relay_compiler_integration/fixtures/resolver_returns_interface_of_live_and_non_live_strong_model_type.expected", input, expected).await; } +#[tokio::test] +async fn resolver_returns_plural_server_type_invalid() { + let input = include_str!("relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.input"); + let expected = include_str!("relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.expected"); + test_fixture(transform_fixture, file!(), "resolver_returns_plural_server_type.invalid.input", "relay_compiler_integration/fixtures/resolver_returns_plural_server_type.invalid.expected", input, expected).await; +} + #[tokio::test] async fn resolver_returns_union_of_cse() { let input = include_str!("relay_compiler_integration/fixtures/resolver_returns_union_of_cse.input"); diff --git a/compiler/crates/relay-config/Cargo.toml b/compiler/crates/relay-config/Cargo.toml index c9630a4f6391c..161df4220ddd3 100644 --- a/compiler/crates/relay-config/Cargo.toml +++ b/compiler/crates/relay-config/Cargo.toml @@ -15,8 +15,8 @@ globset = { version = "0.4.13", features = ["serde1"] } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } intern = { path = "../intern" } pathdiff = "0.2" -regex = "1.9.2" +regex = "1.11.1" schemars = { version = "0.8.21", features = ["indexmap2"] } serde = { version = "1.0.185", features = ["derive", "rc"] } -serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } +serde_json = { version = "1.0.140", features = ["float_roundtrip", "unbounded_depth"] } strum = { version = "0.26.2", features = ["derive"] } diff --git a/compiler/crates/relay-config/src/project_config.rs b/compiler/crates/relay-config/src/project_config.rs index f5ff25026b239..0570772c27b6d 100644 --- a/compiler/crates/relay-config/src/project_config.rs +++ b/compiler/crates/relay-config/src/project_config.rs @@ -220,6 +220,10 @@ pub struct SchemaConfig { /// The name of the directive indicating fields that cannot be selected #[serde(default = "default_unselectable_directive_name")] pub unselectable_directive_name: DirectiveName, + + /// If we should select __token field on fetchable types + #[serde(default = "default_enable_token_field")] + pub enable_token_field: bool, } fn default_node_interface_id_field() -> StringKey { @@ -234,6 +238,10 @@ fn default_unselectable_directive_name() -> DirectiveName { DirectiveName("unselectable".intern()) } +fn default_enable_token_field() -> bool { + false +} + impl Default for SchemaConfig { fn default() -> Self { Self { @@ -243,6 +251,7 @@ impl Default for SchemaConfig { node_interface_id_variable_name: default_node_interface_id_variable_name(), non_node_id_fields: None, unselectable_directive_name: default_unselectable_directive_name(), + enable_token_field: default_enable_token_field(), } } } @@ -405,7 +414,8 @@ impl Debug for ProjectConfig { } impl ProjectConfig { - /// This function will create a correct path for an artifact based on the project configuration + /// Gets the correct path for a generated artifact based on its originating source file's + /// location, and the project's configuration. pub fn create_path_for_artifact( &self, source_file: SourceLocationKey, @@ -435,6 +445,7 @@ impl ProjectConfig { } } + /// Generates a path for an artifact file based on a definition name and its location. pub fn artifact_path_for_definition( &self, definition_name: WithLocation>, @@ -459,6 +470,7 @@ impl ProjectConfig { } } + /// Generates a path for an artifact file that is specific to the programming language being used. pub fn path_for_language_specific_artifact( &self, source_file: SourceLocationKey, diff --git a/compiler/crates/relay-docblock/Cargo.toml b/compiler/crates/relay-docblock/Cargo.toml index 782aa4cb03a86..5d7a0e69ebdfa 100644 --- a/compiler/crates/relay-docblock/Cargo.toml +++ b/compiler/crates/relay-docblock/Cargo.toml @@ -24,12 +24,12 @@ errors = { path = "../errors" } graphql-ir = { path = "../graphql-ir" } graphql-syntax = { path = "../graphql-syntax" } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } relay-config = { path = "../relay-config" } relay-schema = { path = "../relay-schema" } schema = { path = "../schema" } serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] extract-graphql = { path = "../extract-graphql" } diff --git a/compiler/crates/relay-docblock/src/docblock_ir.rs b/compiler/crates/relay-docblock/src/docblock_ir.rs index 686a7fe362f9b..f54008930660d 100644 --- a/compiler/crates/relay-docblock/src/docblock_ir.rs +++ b/compiler/crates/relay-docblock/src/docblock_ir.rs @@ -404,6 +404,7 @@ fn parse_terse_relay_resolver_ir( fragment_arguments, source_hash, type_confirmed: false, + property_lookup_name: None, }) } diff --git a/compiler/crates/relay-docblock/src/ir.rs b/compiler/crates/relay-docblock/src/ir.rs index c31c728ffa778..fadd9704a3ba4 100644 --- a/compiler/crates/relay-docblock/src/ir.rs +++ b/compiler/crates/relay-docblock/src/ir.rs @@ -28,10 +28,12 @@ use docblock_shared::INJECT_FRAGMENT_DATA_ARGUMENT_NAME; use docblock_shared::LIVE_ARGUMENT_NAME; use docblock_shared::RELAY_RESOLVER_DIRECTIVE_NAME; use docblock_shared::RELAY_RESOLVER_MODEL_DIRECTIVE_NAME; +use docblock_shared::RELAY_RESOLVER_MODEL_GENERATED_ID_FIELD_DIRECTIVE_NAME; use docblock_shared::RELAY_RESOLVER_MODEL_INSTANCE_FIELD; use docblock_shared::RELAY_RESOLVER_SOURCE_HASH; use docblock_shared::RELAY_RESOLVER_SOURCE_HASH_VALUE; use docblock_shared::RELAY_RESOLVER_WEAK_OBJECT_DIRECTIVE; +use docblock_shared::RESOLVER_PROPERTY_LOOKUP_NAME; use docblock_shared::RESOLVER_VALUE_SCALAR_NAME; use docblock_shared::TYPE_CONFIRMED_ARGUMENT_NAME; use graphql_ir::FragmentDefinitionName; @@ -373,6 +375,7 @@ trait ResolverIr: Sized { fn source_hash(&self) -> ResolverSourceHash; fn semantic_non_null(&self) -> Option; fn type_confirmed(&self) -> bool; + fn property_lookup_name(&self) -> Option>; fn to_graphql_schema_ast( self, @@ -514,7 +517,13 @@ trait ResolverIr: Sized { } } } - + let property_lookup = self.property_lookup_name(); + if let Some(property_lookup) = property_lookup { + arguments.push(string_argument( + RESOLVER_PROPERTY_LOOKUP_NAME.0, + property_lookup, + )); + } let schema = project_config.schema; if let Some(output_type) = self.output_type() { @@ -821,6 +830,7 @@ pub struct TerseRelayResolverIr { /// Indicates that the extraction method used has already validated that the /// implementaiton matches the GraphQL types. pub type_confirmed: bool, + pub property_lookup_name: Option>, } impl ResolverIr for TerseRelayResolverIr { @@ -926,6 +936,10 @@ impl ResolverIr for TerseRelayResolverIr { fn type_confirmed(&self) -> bool { self.type_confirmed } + + fn property_lookup_name(&self) -> Option> { + self.property_lookup_name + } } impl ResolverTypeDefinitionIr for TerseRelayResolverIr { @@ -1118,6 +1132,10 @@ impl ResolverIr for LegacyVerboseResolverIr { fn type_confirmed(&self) -> bool { false } + + fn property_lookup_name(&self) -> Option> { + None + } } impl ResolverTypeDefinitionIr for LegacyVerboseResolverIr { @@ -1177,7 +1195,14 @@ impl StrongObjectIr { exclamation: dummy_token(span), })), arguments: None, - directives: vec![], + directives: vec![ConstantDirective { + span, + at: dummy_token(span), + name: string_key_as_identifier( + RELAY_RESOLVER_MODEL_GENERATED_ID_FIELD_DIRECTIVE_NAME.0, + ), + arguments: None, + }], description: None, hack_source: None, span, @@ -1267,6 +1292,10 @@ impl ResolverIr for StrongObjectIr { fn type_confirmed(&self) -> bool { self.type_confirmed } + + fn property_lookup_name(&self) -> Option> { + None + } } /// Relay Resolver docblock representing a "model" type for a weak object @@ -1456,6 +1485,10 @@ impl ResolverIr for WeakObjectIr { fn type_confirmed(&self) -> bool { self.type_confirmed } + + fn property_lookup_name(&self) -> Option> { + None + } } fn string_argument(name: StringKey, value: WithLocation) -> ConstantArgument { diff --git a/compiler/crates/relay-docblock/src/validate_resolver_schema.rs b/compiler/crates/relay-docblock/src/validate_resolver_schema.rs index 9c6ed78ddbb82..0293a8a522940 100644 --- a/compiler/crates/relay-docblock/src/validate_resolver_schema.rs +++ b/compiler/crates/relay-docblock/src/validate_resolver_schema.rs @@ -125,7 +125,7 @@ fn is_valid_mutation_resolver_return_type(type_: &TypeReference) -> bool { TypeReference::NonNull(non_null_type) => { // note: this should be unreachable since we already disallow relay resolvers to return non-nullable types // - implement this anyway in case that changes in the future - return is_valid_mutation_resolver_return_type(non_null_type.as_ref()); + is_valid_mutation_resolver_return_type(non_null_type.as_ref()) } } } diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-args.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-args.expected index 98ec348e24bfd..adb2ec5cdcbec 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-args.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-args.expected @@ -128,6 +128,7 @@ Field( "ff0b47b51f0011ae9def59af3e3792a3", ), type_confirmed: false, + property_lookup_name: None, }, ), ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-disallow-non-nullable-list-item.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-disallow-non-nullable-list-item.expected index 23601aad555b3..a9482f9f75107 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-disallow-non-nullable-list-item.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-disallow-non-nullable-list-item.expected @@ -85,6 +85,7 @@ Field( "12e28b8739ff3ab018186a28de3ca726", ), type_confirmed: false, + property_lookup_name: None, }, ), ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-non-nullable.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-non-nullable.expected index 356d89db6d081..fd91ed50f3db5 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-non-nullable.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-non-nullable.expected @@ -74,6 +74,7 @@ Field( "ac789e28bceef3eeaab77ae5203f43a6", ), type_confirmed: false, + property_lookup_name: None, }, ), ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-semantic-non-null.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-semantic-non-null.expected index f7dc9d7978a15..f40b2d5120fdd 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-semantic-non-null.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver-semantic-non-null.expected @@ -114,6 +114,7 @@ Field( "ba2a3b6d7c4294fef33f921df3b20065", ), type_confirmed: false, + property_lookup_name: None, }, ), ) diff --git a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver.expected b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver.expected index eced4a153ac1e..e0f413dae3f19 100644 --- a/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver.expected +++ b/compiler/crates/relay-docblock/tests/parse/fixtures/terse-relay-resolver.expected @@ -80,6 +80,7 @@ Field( "0a9950ad1f952f5777b27604738fcf91", ), type_confirmed: false, + property_lookup_name: None, }, ), ) diff --git a/compiler/crates/relay-docblock/tests/to_schema.rs b/compiler/crates/relay-docblock/tests/to_schema.rs index 9669b8e3f0993..5e6c7db4af6af 100644 --- a/compiler/crates/relay-docblock/tests/to_schema.rs +++ b/compiler/crates/relay-docblock/tests/to_schema.rs @@ -39,8 +39,7 @@ pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result let executable_documents = js_features .iter() - .enumerate() - .filter_map(|(_, source)| match source { + .filter_map(|source| match source { JavaScriptSourceFeature::GraphQL(source) => Some( parse_executable(&source.text_source().text, SourceLocationKey::Generated) .map_err(|diagnostics| { diff --git a/compiler/crates/relay-docblock/tests/to_schema/fixtures/legacy-relay-resolver-with-root-fragment-on-model.expected b/compiler/crates/relay-docblock/tests/to_schema/fixtures/legacy-relay-resolver-with-root-fragment-on-model.expected index f3a1b885e0429..13481f35cc57f 100644 --- a/compiler/crates/relay-docblock/tests/to_schema/fixtures/legacy-relay-resolver-with-root-fragment-on-model.expected +++ b/compiler/crates/relay-docblock/tests/to_schema/fixtures/legacy-relay-resolver-with-root-fragment-on-model.expected @@ -26,7 +26,7 @@ graphql` ` ==================================== OUTPUT =================================== type MyType @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(fragment_name: "MyType__id", generated_fragment: true, inject_fragment_data: "id", import_name: "MyType", import_path: "/path/to/test/fixture/legacy-relay-resolver-with-root-fragment-on-model.js") @resolver_source_hash(value: "b81f253a757aaba36955be6d8e224c2a") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-implements.expected b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-implements.expected index 5c2c1ede03bd3..170f1af4b2075 100644 --- a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-implements.expected +++ b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-implements.expected @@ -20,6 +20,6 @@ interface IFoo { ` ==================================== OUTPUT =================================== type ClientUser implements IFoo @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(fragment_name: "ClientUser__id", generated_fragment: true, inject_fragment_data: "id", import_name: "ClientUser", import_path: "/path/to/test/fixture/relay-resolver-strong-object-with-implements.js") @resolver_source_hash(value: "76be3b85f11135352a0d3a5726418956") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-multiple-implements.expected b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-multiple-implements.expected index 9c25186d33d87..365179a1937dd 100644 --- a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-multiple-implements.expected +++ b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object-with-multiple-implements.expected @@ -26,6 +26,6 @@ interface IBar { ` ==================================== OUTPUT =================================== type ClientUser implements IFoo & IBar @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(fragment_name: "ClientUser__id", generated_fragment: true, inject_fragment_data: "id", import_name: "ClientUser", import_path: "/path/to/test/fixture/relay-resolver-strong-object-with-multiple-implements.js") @resolver_source_hash(value: "1b7346b6155a43514be2946721ff59fb") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object.expected b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object.expected index 4ef88ea2cb954..b549ce206784c 100644 --- a/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object.expected +++ b/compiler/crates/relay-docblock/tests/to_schema/fixtures/relay-resolver-strong-object.expected @@ -11,6 +11,6 @@ */ ==================================== OUTPUT =================================== type ClientUser @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(fragment_name: "ClientUser__id", generated_fragment: true, inject_fragment_data: "id", import_name: "ClientUser", import_path: "/path/to/test/fixture/relay-resolver-strong-object.js") @resolver_source_hash(value: "b1c8ae1937aed7425f5a87a4762ad83d") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-docblock/tests/to_schema/fixtures/terse-relay-resolver-with-root-fragment-on-model.expected b/compiler/crates/relay-docblock/tests/to_schema/fixtures/terse-relay-resolver-with-root-fragment-on-model.expected index ac003540d6f49..ed4f871311cd0 100644 --- a/compiler/crates/relay-docblock/tests/to_schema/fixtures/terse-relay-resolver-with-root-fragment-on-model.expected +++ b/compiler/crates/relay-docblock/tests/to_schema/fixtures/terse-relay-resolver-with-root-fragment-on-model.expected @@ -22,7 +22,7 @@ graphql` ` ==================================== OUTPUT =================================== type MyType @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(fragment_name: "MyType__id", generated_fragment: true, inject_fragment_data: "id", import_name: "MyType", import_path: "/path/to/test/fixture/terse-relay-resolver-with-root-fragment-on-model.js") @resolver_source_hash(value: "b81f253a757aaba36955be6d8e224c2a") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-lsp/Cargo.toml b/compiler/crates/relay-lsp/Cargo.toml index 873106de93069..d89ff250d7252 100644 --- a/compiler/crates/relay-lsp/Cargo.toml +++ b/compiler/crates/relay-lsp/Cargo.toml @@ -27,8 +27,8 @@ graphql-syntax = { path = "../graphql-syntax" } graphql-text-printer = { path = "../graphql-text-printer" } graphql-watchman = { path = "../graphql-watchman" } intern = { path = "../intern" } -itertools = "0.13.0" -lazy_static = "1.4" +itertools = "0.14.0" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } log = { version = "0.4.22", features = ["kv_unstable"] } lsp-server = "0.7.2" lsp-types = "0.94.1" @@ -45,7 +45,7 @@ schema-diff = { path = "../schema-diff" } schema-documentation = { path = "../schema-documentation" } schema-print = { path = "../schema-print" } serde = { version = "1.0.185", features = ["derive", "rc"] } -serde_json = { version = "1.0.132", features = ["float_roundtrip", "unbounded_depth"] } +serde_json = { version = "1.0.140", features = ["float_roundtrip", "unbounded_depth"] } tokio = { version = "1.41.0", features = ["full", "test-util", "tracing"] } [dev-dependencies] diff --git a/compiler/crates/relay-lsp/src/lib.rs b/compiler/crates/relay-lsp/src/lib.rs index b486a3b52d38c..ca95d6737fede 100644 --- a/compiler/crates/relay-lsp/src/lib.rs +++ b/compiler/crates/relay-lsp/src/lib.rs @@ -126,11 +126,11 @@ pub fn diagnostics_to_code_actions( let mut all_actions = vec![]; for param in published_params { for diagnostic in param.diagnostics { - if let Some(action) = get_code_actions_from_diagnostic(¶m.uri, diagnostic) - .unwrap() - .first() - { - all_actions.push(action.clone()); + if let Some(actions) = get_code_actions_from_diagnostic(¶m.uri, diagnostic) { + // If there are multiple actions for a diagnostic, we only send the first one. + if let Some(action) = actions.first() { + all_actions.push(action.clone()); + } } } } diff --git a/compiler/crates/relay-lsp/src/server.rs b/compiler/crates/relay-lsp/src/server.rs index e9684fa0cca84..2d07107e37abc 100644 --- a/compiler/crates/relay-lsp/src/server.rs +++ b/compiler/crates/relay-lsp/src/server.rs @@ -50,6 +50,7 @@ use lsp_types::request::References; use lsp_types::request::Rename; use lsp_types::request::ResolveCompletionItem; use lsp_types::request::Shutdown; +use lsp_types::CodeActionOptions; use lsp_types::CodeActionProviderCapability; use lsp_types::CompletionOptions; use lsp_types::InitializeParams; @@ -132,7 +133,10 @@ pub fn initialize(connection: &Connection) -> LSPProcessResult hover_provider: Some(lsp_types::HoverProviderCapability::Simple(true)), definition_provider: Some(lsp_types::OneOf::Left(true)), references_provider: Some(lsp_types::OneOf::Left(true)), - code_action_provider: Some(CodeActionProviderCapability::Simple(true)), + code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions { + code_action_kinds: Some(vec![lsp_types::CodeActionKind::QUICKFIX]), + ..Default::default() + })), inlay_hint_provider: Some(lsp_types::OneOf::Left(true)), ..Default::default() }; diff --git a/compiler/crates/relay-lsp/src/server/lsp_state.rs b/compiler/crates/relay-lsp/src/server/lsp_state.rs index 57ae809eac3ca..ab796348984f0 100644 --- a/compiler/crates/relay-lsp/src/server/lsp_state.rs +++ b/compiler/crates/relay-lsp/src/server/lsp_state.rs @@ -48,7 +48,6 @@ use relay_docblock::parse_docblock_ast; use relay_docblock::ParseOptions; use relay_transforms::apply_transforms; use relay_transforms::deprecated_fields_for_executable_definition; -use relay_transforms::disallow_required_on_non_null_field_for_executable_definition; use schema::SDLSchema; use schema_documentation::CombinedSchemaDocumentation; use schema_documentation::SchemaDocumentation; @@ -274,17 +273,11 @@ impl Err(BuildProjectFailure::Error( + BuildProjectError::ValidationErrors { + errors: diagnostics, + project_name: project_config.name, + }, + )), + // Compilation-blocking validation errors + Err(diagnostics) => Err(BuildProjectFailure::Error( + BuildProjectError::ValidationErrors { + errors: diagnostics, + project_name: project_config.name, + }, + )), + }?; Ok(()) } diff --git a/compiler/crates/relay-lsp/tests/rename.rs b/compiler/crates/relay-lsp/tests/rename.rs index 5f6f3b6bf1634..919d4b7f11ff8 100644 --- a/compiler/crates/relay-lsp/tests/rename.rs +++ b/compiler/crates/relay-lsp/tests/rename.rs @@ -70,7 +70,7 @@ fn rename_locations(locations: Vec, source: &str) -> String { let start = (span.start as i32 + offset) as usize; let end = (span.end as i32 + offset) as usize; - source_with_renames.replace_range(start..end, &renamed_key); + source_with_renames.replace_range(start..end, renamed_key); let original_length = end as i32 - start as i32; offset += renamed_key_length - original_length; diff --git a/compiler/crates/relay-saved-state-loader/Cargo.toml b/compiler/crates/relay-saved-state-loader/Cargo.toml index 6c68f1e55365f..2a9a778c534a2 100644 --- a/compiler/crates/relay-saved-state-loader/Cargo.toml +++ b/compiler/crates/relay-saved-state-loader/Cargo.toml @@ -9,5 +9,5 @@ repository = "https://github.com/facebook/relay" license = "MIT" [dependencies] -async-trait = "0.1.71" -serde_bser = "0.3" +async-trait = "0.1.86" +serde_bser = "0.4" diff --git a/compiler/crates/relay-schema-generation/Cargo.toml b/compiler/crates/relay-schema-generation/Cargo.toml index f0b2cbd9b341d..ff5bb9a2de197 100644 --- a/compiler/crates/relay-schema-generation/Cargo.toml +++ b/compiler/crates/relay-schema-generation/Cargo.toml @@ -29,13 +29,13 @@ hermes_estree = { git = "https://github.com/facebook/hermes.git" } hermes_parser = { git = "https://github.com/facebook/hermes.git" } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } relay-config = { path = "../relay-config" } relay-docblock = { path = "../relay-docblock" } -rustc-hash = "1.1.0" +rustc-hash = "2.1.0" schema-extractor = { path = "../schema-extractor" } serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] extract-graphql = { path = "../extract-graphql" } diff --git a/compiler/crates/relay-schema-generation/src/errors.rs b/compiler/crates/relay-schema-generation/src/errors.rs index 7e98c02ee4611..315426aa6fcb9 100644 --- a/compiler/crates/relay-schema-generation/src/errors.rs +++ b/compiler/crates/relay-schema-generation/src/errors.rs @@ -98,4 +98,12 @@ pub enum SchemaGenerationError { module_name: StringKey, import_type: JSImportType, }, + #[error( + "The key of a property lookup resolver defined with @gqlField must be an identifier (not a string or computed value)." + )] + ExpectedPropertyLookupToBeIdentifer, + #[error( + "This field is a property lookup but has an import for a GraphQL fragment used in the resolver. This is not allowed." + )] + ExpectedResolverFunctionWithRootFragment, } diff --git a/compiler/crates/relay-schema-generation/src/find_property_lookup_resolvers.rs b/compiler/crates/relay-schema-generation/src/find_property_lookup_resolvers.rs new file mode 100644 index 0000000000000..c88a652a0fff3 --- /dev/null +++ b/compiler/crates/relay-schema-generation/src/find_property_lookup_resolvers.rs @@ -0,0 +1,121 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#![deny(warnings)] +#![deny(clippy::all)] + +use ::intern::string_key::Intern; +use ::intern::string_key::StringKey; +use common::Diagnostic; +use common::Location; +use common::SourceLocationKey; +use common::Span; +use common::WithLocation; +use docblock_shared::ResolverSourceHash; +use docblock_syntax::parse_docblock; +use docblock_syntax::DocblockAST; +use fnv::FnvHashMap; +use hermes_estree::ObjectTypePropertyKey; +use hermes_estree::Range; +use hermes_estree::SourceRange; +use hermes_estree::Visitor; + +use crate::get_deprecated; +use crate::get_description; +use crate::FieldDefinitionInfo; +use crate::SchemaGenerationError; +use crate::UnresolvedFieldDefinition; + +fn source_range_to_span(source_range: SourceRange) -> Span { + Span { + start: source_range.start, + end: source_range.end, + } +} + +pub struct PropertyVisitor<'a> { + pub location: SourceLocationKey, + source_hash: ResolverSourceHash, + pub errors: Vec, + entity_name: WithLocation, + resolver_node_ranges: &'a FnvHashMap, + pub field_definitions: Vec, +} + +impl<'a> PropertyVisitor<'a> { + pub fn new( + source_module_path: &str, + source_hash: ResolverSourceHash, + entity_name: WithLocation, + resolver_node_ranges: &'a FnvHashMap, + ) -> Self { + Self { + location: SourceLocationKey::standalone(source_module_path), + source_hash, + errors: vec![], + entity_name, + resolver_node_ranges, + field_definitions: vec![], + } + } +} + +impl Visitor<'_> for PropertyVisitor<'_> { + fn visit_object_type_property(&mut self, ast: &'_ hermes_estree::ObjectTypeProperty) { + if self.resolver_node_ranges.contains_key(&ast.range) { + let field_name = match &ast.key { + ObjectTypePropertyKey::Identifier(id) => WithLocation::from_span( + self.location, + source_range_to_span(id.range), + id.name.clone().intern(), + ), + ObjectTypePropertyKey::_Literal(lit) => { + self.errors.push(Diagnostic::error( + SchemaGenerationError::ExpectedPropertyLookupToBeIdentifer, + Location::new(self.location, source_range_to_span(lit.range())), + )); + return; + } + }; + let (comment, comment_range) = self.resolver_node_ranges.get(&ast.range).unwrap(); + let docblock = match parse_docblock(comment, self.location) { + Ok(docblock) => docblock, + Err(err) => { + self.errors.extend(err); + return; + } + }; + let description = match get_description(&docblock, *comment_range) { + Ok(description) => description, + Err(err) => { + self.errors.extend(err); + return; + } + }; + let deprecated = get_deprecated(&docblock); + let alias = get_aliased_field_name(&docblock); + let field_definition = UnresolvedFieldDefinition { + field_name: alias.unwrap_or(field_name), + entity_name: Some(self.entity_name), + return_type: ast.value.clone(), + source_hash: self.source_hash, + description, + deprecated, + entity_type: None, + field_info: FieldDefinitionInfo::PropertyLookupInfo { + property_name: field_name, + }, + }; + self.field_definitions.push(field_definition); + } + } +} + +fn get_aliased_field_name(docblock: &DocblockAST) -> Option> { + let aliased_field = docblock.find_field("gqlField".intern()); + aliased_field.and_then(|f| f.field_value) +} diff --git a/compiler/crates/relay-schema-generation/src/lib.rs b/compiler/crates/relay-schema-generation/src/lib.rs index 50eb81d761b39..b49bb4a82a333 100644 --- a/compiler/crates/relay-schema-generation/src/lib.rs +++ b/compiler/crates/relay-schema-generation/src/lib.rs @@ -10,6 +10,7 @@ #![deny(clippy::all)] mod errors; +mod find_property_lookup_resolvers; mod find_resolver_imports; use std::collections::hash_map::Entry; @@ -41,6 +42,7 @@ use find_resolver_imports::JSImportType; use find_resolver_imports::ModuleResolution; use find_resolver_imports::ModuleResolutionKey; use fnv::FnvBuildHasher; +use fnv::FnvHashMap; use graphql_ir::FragmentDefinitionName; use graphql_syntax::ConstantArgument; use graphql_syntax::ConstantDirective; @@ -59,6 +61,7 @@ use graphql_syntax::Token; use graphql_syntax::TokenKind; use graphql_syntax::TypeAnnotation; use hermes_comments::find_nodes_after_comments; +use hermes_comments::AttachedComments; use hermes_estree::Declaration; use hermes_estree::FlowTypeAnnotation; use hermes_estree::Function; @@ -71,6 +74,7 @@ use hermes_estree::Range; use hermes_estree::SourceRange; use hermes_estree::TypeAlias; use hermes_estree::TypeAnnotationEnum; +use hermes_estree::Visitor; use hermes_parser::parse; use hermes_parser::ParseResult; use hermes_parser::ParserDialect; @@ -91,6 +95,8 @@ use relay_docblock::WeakObjectIr; use rustc_hash::FxHashMap; use schema_extractor::SchemaExtractor; +use crate::find_property_lookup_resolvers::PropertyVisitor; + pub static LIVE_FLOW_TYPE_NAME: &str = "LiveState"; type FnvIndexMap = IndexMap; @@ -134,17 +140,27 @@ pub struct RelayResolverExtractor { custom_scalar_map: FnvIndexMap, } +enum FieldDefinitionInfo { + ResolverFunctionInfo { + arguments: Option, + is_live: Option, + root_fragment: Option<(WithLocation, Vec)>, + }, + PropertyLookupInfo { + // If an alias is used, this may differ from the field name + property_name: WithLocation, + }, +} + struct UnresolvedFieldDefinition { entity_name: Option>, field_name: WithLocation, return_type: FlowTypeAnnotation, - arguments: Option, source_hash: ResolverSourceHash, - is_live: Option, description: Option>, deprecated: Option, - root_fragment: Option<(WithLocation, Vec)>, entity_type: Option>, + field_info: FieldDefinitionInfo, } impl Default for RelayResolverExtractor { @@ -233,6 +249,15 @@ impl RelayResolverExtractor { let module_resolution = import_export_visitor.get_module_resolution(&ast)?; let attached_comments = find_nodes_after_comments(&ast, &comments); + let (gql_field_comments, attached_comments): (AttachedComments<'_>, AttachedComments<'_>) = + attached_comments + .into_iter() + .partition(|(comment, _, _, _)| comment.contains("@gqlField")); + + let gql_comments = + FnvHashMap::from_iter(gql_field_comments.into_iter().map( + |(comment, comment_range, _, node_range)| (node_range, (comment, comment_range)), + )); let result = try_all( attached_comments @@ -280,13 +305,15 @@ impl RelayResolverExtractor { entity_name, field_name: name, return_type, - arguments, source_hash, - is_live, description, deprecated, - root_fragment: None, entity_type: None, + field_info: FieldDefinitionInfo::ResolverFunctionInfo { + arguments, + is_live, + root_fragment: None, + }, }, )? } else { @@ -305,6 +332,25 @@ impl RelayResolverExtractor { type_alias, }) => { let name = resolver_value.field_value.unwrap_or(field_name); + let mut prop_visitor = PropertyVisitor::new( + source_module_path, + source_hash, + name, + &gql_comments, + ); + prop_visitor.visit_flow_type_annotation(&type_alias); + if !prop_visitor.errors.is_empty() { + return Err(prop_visitor.errors); + } + let field_definitions: Vec<( + UnresolvedFieldDefinition, + SourceLocationKey, + )> = prop_visitor + .field_definitions + .into_iter() + .map(|def| (def, prop_visitor.location)) + .collect(); + self.add_weak_type_definition( name, type_alias, @@ -312,7 +358,8 @@ impl RelayResolverExtractor { source_module_path, description, false, - )? + )?; + self.unresolved_field_definitions.extend(field_definitions); } } Ok(()) @@ -379,27 +426,51 @@ impl RelayResolverExtractor { // Special case: we attach the field to the `Query` type when there is no entity WithLocation::new(field.field_name.location, intern!("Query")) }; - let arguments = if let Some(args) = field.arguments { - Some(flow_type_to_field_arguments( - source_location, - &self.custom_scalar_map, - &args, - module_resolution, - &self.type_definitions, - )?) - } else { - None + let property_lookup_name = match field.field_info { + FieldDefinitionInfo::PropertyLookupInfo { property_name } => { + Some(property_name) + } + FieldDefinitionInfo::ResolverFunctionInfo { .. } => None, }; - if let (Some(field_arguments), Some((root_fragment, fragment_arguments))) = - (&arguments, &field.root_fragment) - { - relay_docblock::validate_fragment_arguments( - source_location, - field_arguments, - root_fragment.location.source_location(), - fragment_arguments, - )?; - } + let (arguments, is_live, (root_fragment, fragment_arguments)) = + match field.field_info { + FieldDefinitionInfo::ResolverFunctionInfo { + arguments, + is_live, + root_fragment, + } => { + let args = if let Some(args) = arguments { + Some(flow_type_to_field_arguments( + source_location, + &self.custom_scalar_map, + &args, + module_resolution, + &self.type_definitions, + )?) + } else { + None + }; + + if let ( + Some(field_arguments), + Some((root_fragment, fragment_arguments)), + ) = (&args, &root_fragment) + { + relay_docblock::validate_fragment_arguments( + source_location, + field_arguments, + root_fragment.location.source_location(), + fragment_arguments, + )?; + } + + (args, is_live, root_fragment.unzip()) + } + FieldDefinitionInfo::PropertyLookupInfo { .. } => { + (None, None, (None, None)) + } + }; + let live = is_live.map(|loc| UnpopulatedIrField { key_location: loc }); let description_node = field.description.map(|desc| StringNode { token: Token { span: desc.location.span(), @@ -425,10 +496,6 @@ impl RelayResolverExtractor { hack_source: None, span: field.field_name.location.span(), }; - let live = field - .is_live - .map(|loc| UnpopulatedIrField { key_location: loc }); - let (root_fragment, fragment_arguments) = field.root_fragment.unzip(); self.resolved_field_definitions.push(TerseRelayResolverIr { field: field_definition, type_, @@ -443,6 +510,7 @@ impl RelayResolverExtractor { field.field_name.location, ), type_confirmed: true, + property_lookup_name, }); Ok(()) }), @@ -489,8 +557,23 @@ impl RelayResolverExtractor { ); let fragment_arguments = relay_docblock::extract_fragment_arguments(&fragment_definition).transpose()?; - field_definition.root_fragment = - Some((fragment, fragment_arguments.unwrap_or(vec![]))); + field_definition.field_info = match field_definition.field_info { + FieldDefinitionInfo::ResolverFunctionInfo { + arguments, + is_live, + root_fragment: _, + } => FieldDefinitionInfo::ResolverFunctionInfo { + arguments, + is_live, + root_fragment: Some((fragment, fragment_arguments.unwrap_or(vec![]))), + }, + FieldDefinitionInfo::PropertyLookupInfo { .. } => { + return Err(vec![Diagnostic::error( + SchemaGenerationError::ExpectedResolverFunctionWithRootFragment, + entity_name.location, + )]); + } + } } } self.unresolved_field_definitions @@ -623,17 +706,17 @@ impl RelayResolverExtractor { entity_name: Some(name), field_name, return_type: field_type.clone(), - arguments: None, source_hash, - is_live: None, description, deprecated: None, - root_fragment: None, entity_type: Some( weak_object .type_name .name_with_location(weak_object.location.source_location()), ), + field_info: FieldDefinitionInfo::PropertyLookupInfo { + property_name: field_name, + }, }, self.current_location, )); diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/arguments.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/arguments.expected index 465a0a0e176fa..2ff923ce9cb4f 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/arguments.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/arguments.expected @@ -123,6 +123,7 @@ Field( "9eb0075d1ca5f38ce3ae8a364b4fb1be", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -236,6 +237,7 @@ Field( "9eb0075d1ca5f38ce3ae8a364b4fb1be", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -276,7 +278,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "9eb0075d1ca5f38ce3ae8a364b4fb1be") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/built-in-scalar-id.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/built-in-scalar-id.expected index 37c048ee40ca4..e1cb06c3f6109 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/built-in-scalar-id.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/built-in-scalar-id.expected @@ -86,6 +86,7 @@ Field( "a9744194670e59356ad37913eff9defe", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -126,6 +127,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "a9744194670e59356ad37913eff9defe") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/conflicting-type-definitions.error.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/conflicting-type-definitions.error.expected index 382f083978619..2310a856619c1 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/conflicting-type-definitions.error.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/conflicting-type-definitions.error.expected @@ -81,7 +81,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "1b432d1f1ef72adb427857abb24a5068") @unselectable(reason: "This field is intended only for Relay's internal use") } @@ -90,31 +90,31 @@ Type( WeakObjectType( WeakObjectIr { type_name: Identifier { - span: 104:111, + span: 39:46, token: Token { - span: 104:111, + span: 39:46, kind: Identifier, }, value: "WeakCat", }, - rhs_location: AnotherWeakCat.js:104:111, + rhs_location: WeakCat.js:39:46, description: None, hack_source: None, deprecated: None, - location: AnotherWeakCat.js:104:111, + location: WeakCat.js:39:46, implements_interfaces: [], source_hash: ResolverSourceHash( - "fbdfc15b898dadb276e02cb59997fd3e", + "d87c48cc6e55a86fc69fd0d1f73d6bea", ), type_confirmed: true, }, ), ) -scalar WeakCatModel @__RelayCustomScalar(path: "AnotherWeakCat.js", export_name: "WeakCat") +scalar WeakCatModel @__RelayCustomScalar(path: "WeakCat.js", export_name: "WeakCat") type WeakCat @__RelayResolverModel @RelayOutputType @__RelayWeakObject { - __relay_model_instance: WeakCatModel! @resolver_source_hash(value: "fbdfc15b898dadb276e02cb59997fd3e") @unselectable(reason: "This field is intended only for Relay's internal use") + __relay_model_instance: WeakCatModel! @resolver_source_hash(value: "d87c48cc6e55a86fc69fd0d1f73d6bea") @unselectable(reason: "This field is intended only for Relay's internal use") } @@ -137,8 +137,8 @@ type WeakCat @__RelayResolverModel @RelayOutputType @__RelayWeakObject { ✖︎ Duplicate definition for type 'WeakCatModel'. - WeakCat.js:5:13 - 4 │ */ - 5 │ export type WeakCat = { + AnotherWeakCat.js:6:13 + 5 │ */ + 6 │ export type WeakCat = { │ ^^^^^^^ - 6 │ name: string + 7 │ name: string diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global-shadow.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global-shadow.expected index 481e8a722d434..f221cabf3ef1f 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global-shadow.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global-shadow.expected @@ -76,6 +76,7 @@ Field( "b34abe1ebe87f22729175fd53c228fc1", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -116,7 +117,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "b34abe1ebe87f22729175fd53c228fc1") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global.expected index 7d46be9b25603..2c7cdf1596219 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar-global.expected @@ -68,6 +68,7 @@ Field( "dfc8ee95a857f2fd4e31a1f955c041c9", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -108,6 +109,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "dfc8ee95a857f2fd4e31a1f955c041c9") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar.expected index 5efbe1fd2ba4c..ff103e6eb0493 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/custom-scalar.expected @@ -80,6 +80,7 @@ Field( "69e6ff1ceadd103da3b3b9a805681c7c", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -180,6 +181,7 @@ Field( "69e6ff1ceadd103da3b3b9a805681c7c", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -220,6 +222,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "69e6ff1ceadd103da3b3b9a805681c7c") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/deprecated.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/deprecated.expected index 485a24add8aa7..39dc40283ed98 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/deprecated.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/deprecated.expected @@ -97,6 +97,7 @@ Field( "dcf10bac1041d7f30f36c2bd311d01b8", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -155,6 +156,7 @@ Field( "dcf10bac1041d7f30f36c2bd311d01b8", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -200,6 +202,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "dcf10bac1041d7f30f36c2bd311d01b8") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/description.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/description.expected index 5cbae24a345cd..7122f0c700bf7 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/description.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/description.expected @@ -93,6 +93,7 @@ Field( "77d8976fca517fd3aea7ae4517ed9579", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -153,6 +154,7 @@ Field( "77d8976fca517fd3aea7ae4517ed9579", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -193,7 +195,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "77d8976fca517fd3aea7ae4517ed9579") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/idof.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/idof.expected index a8e5a47a4f008..e2aa27e3813a3 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/idof.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/idof.expected @@ -92,6 +92,7 @@ Field( "08165d712e1fcab6840e997daaebf69e", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -144,6 +145,7 @@ Field( "08165d712e1fcab6840e997daaebf69e", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -184,7 +186,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "08165d712e1fcab6840e997daaebf69e") @unselectable(reason: "This field is intended only for Relay's internal use") } @@ -221,7 +223,7 @@ Type( ), ) type Dog @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Dog__id", import_name: "Dog", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "08165d712e1fcab6840e997daaebf69e") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/live.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/live.expected index 8cd74bef370cf..b6e547ec4452f 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/live.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/live.expected @@ -78,6 +78,7 @@ Field( "088060a75d59266ad0547d9a0312562f", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -118,6 +119,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "088060a75d59266ad0547d9a0312562f") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/optional-strong-type.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/optional-strong-type.expected index 58d385f156830..9d7ad332eb784 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/optional-strong-type.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/optional-strong-type.expected @@ -57,7 +57,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "4325ac2bef4354788b5ccb1c5f5ffd53") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/plural-optional.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/plural-optional.expected index 8c6364f36b285..1782535abdc4a 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/plural-optional.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/plural-optional.expected @@ -92,6 +92,7 @@ Field( "78b9d79fcbb849dee2ae7a1d6d275e22", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -144,6 +145,7 @@ Field( "78b9d79fcbb849dee2ae7a1d6d275e22", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -184,6 +186,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "b0ce1a838dad74fce5422c930d8d9fc3") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/primitive-types.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/primitive-types.expected index 46f88febe4003..3afe56053829b 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/primitive-types.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/primitive-types.expected @@ -91,6 +91,7 @@ Field( "41bd781893c904ec9352255c4f6e974e", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -143,6 +144,7 @@ Field( "41bd781893c904ec9352255c4f6e974e", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -195,6 +197,7 @@ Field( "41bd781893c904ec9352255c4f6e974e", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -247,6 +250,7 @@ Field( "41bd781893c904ec9352255c4f6e974e", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -287,6 +291,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "41bd781893c904ec9352255c4f6e974e") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/property-lookup.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/property-lookup.expected new file mode 100644 index 0000000000000..b3e24f2fd4190 --- /dev/null +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/property-lookup.expected @@ -0,0 +1,383 @@ +==================================== INPUT ==================================== +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +//- module.js + +/** + * @RelayResolver + */ +export type Cat = { + /** + * @gqlField + * + * This is the full name of the cat + */ + name: string, + /** + * @gqlField + */ + color: string, + /** + * @gqlField + * @deprecated Just use name instead + */ + first_name: number, + /** + * @gqlField other_name + */ + alias: number, +}; +==================================== OUTPUT =================================== +Field( + TerseRelayResolver( + TerseRelayResolverIr { + field: FieldDefinition { + name: Identifier { + span: 17:27, + token: Token { + span: 17:27, + kind: Identifier, + }, + value: "other_name", + }, + type_: Named( + NamedTypeAnnotation { + name: Identifier { + span: 504:510, + token: Token { + span: 504:510, + kind: Identifier, + }, + value: "Float", + }, + }, + ), + arguments: None, + directives: [], + description: None, + hack_source: None, + span: 17:27, + }, + type_: WithLocation { + location: module.js:231:234, + item: "Cat", + }, + root_fragment: None, + deprecated: None, + semantic_non_null: Some( + ConstantDirective { + span: 17:27, + at: Token { + span: 0:0, + kind: Empty, + }, + name: Identifier { + span: 17:27, + token: Token { + span: 0:0, + kind: Empty, + }, + value: "semanticNonNull", + }, + arguments: None, + }, + ), + live: None, + location: module.js:17:27, + fragment_arguments: None, + source_hash: ResolverSourceHash( + "6f05c358daee6821384cbf6c03fcb703", + ), + type_confirmed: true, + property_lookup_name: Some( + WithLocation { + location: module.js:497:502, + item: "alias", + }, + ), + }, + ), +) +extend type Cat { + other_name: Float @relay_resolver(fragment_name: "Cat____relay_model_instance", generated_fragment: true, inject_fragment_data: "__relay_model_instance", type_confirmed: true, has_output_type: true, import_name: "other_name", import_path: "module.js", property_lookup_name: "alias") @resolver_source_hash(value: "6f05c358daee6821384cbf6c03fcb703") @semanticNonNull +} + + +Field( + TerseRelayResolver( + TerseRelayResolverIr { + field: FieldDefinition { + name: Identifier { + span: 311:315, + token: Token { + span: 311:315, + kind: Identifier, + }, + value: "name", + }, + type_: Named( + NamedTypeAnnotation { + name: Identifier { + span: 317:323, + token: Token { + span: 317:323, + kind: Identifier, + }, + value: "String", + }, + }, + ), + arguments: None, + directives: [], + description: Some( + StringNode { + token: Token { + span: 241:308, + kind: Empty, + }, + value: "\nThis is the full name of the cat", + }, + ), + hack_source: None, + span: 311:315, + }, + type_: WithLocation { + location: module.js:231:234, + item: "Cat", + }, + root_fragment: None, + deprecated: None, + semantic_non_null: Some( + ConstantDirective { + span: 311:315, + at: Token { + span: 0:0, + kind: Empty, + }, + name: Identifier { + span: 311:315, + token: Token { + span: 0:0, + kind: Empty, + }, + value: "semanticNonNull", + }, + arguments: None, + }, + ), + live: None, + location: module.js:311:315, + fragment_arguments: None, + source_hash: ResolverSourceHash( + "6f05c358daee6821384cbf6c03fcb703", + ), + type_confirmed: true, + property_lookup_name: Some( + WithLocation { + location: module.js:311:315, + item: "name", + }, + ), + }, + ), +) +extend type Cat { + name: String @relay_resolver(fragment_name: "Cat____relay_model_instance", generated_fragment: true, inject_fragment_data: "__relay_model_instance", type_confirmed: true, has_output_type: true, import_name: "name", import_path: "module.js", property_lookup_name: "name") @resolver_source_hash(value: "6f05c358daee6821384cbf6c03fcb703") @semanticNonNull +} + + +Field( + TerseRelayResolver( + TerseRelayResolverIr { + field: FieldDefinition { + name: Identifier { + span: 354:359, + token: Token { + span: 354:359, + kind: Identifier, + }, + value: "color", + }, + type_: Named( + NamedTypeAnnotation { + name: Identifier { + span: 361:367, + token: Token { + span: 361:367, + kind: Identifier, + }, + value: "String", + }, + }, + ), + arguments: None, + directives: [], + description: None, + hack_source: None, + span: 354:359, + }, + type_: WithLocation { + location: module.js:231:234, + item: "Cat", + }, + root_fragment: None, + deprecated: None, + semantic_non_null: Some( + ConstantDirective { + span: 354:359, + at: Token { + span: 0:0, + kind: Empty, + }, + name: Identifier { + span: 354:359, + token: Token { + span: 0:0, + kind: Empty, + }, + value: "semanticNonNull", + }, + arguments: None, + }, + ), + live: None, + location: module.js:354:359, + fragment_arguments: None, + source_hash: ResolverSourceHash( + "6f05c358daee6821384cbf6c03fcb703", + ), + type_confirmed: true, + property_lookup_name: Some( + WithLocation { + location: module.js:354:359, + item: "color", + }, + ), + }, + ), +) +extend type Cat { + color: String @relay_resolver(fragment_name: "Cat____relay_model_instance", generated_fragment: true, inject_fragment_data: "__relay_model_instance", type_confirmed: true, has_output_type: true, import_name: "color", import_path: "module.js", property_lookup_name: "color") @resolver_source_hash(value: "6f05c358daee6821384cbf6c03fcb703") @semanticNonNull +} + + +Field( + TerseRelayResolver( + TerseRelayResolverIr { + field: FieldDefinition { + name: Identifier { + span: 437:447, + token: Token { + span: 437:447, + kind: Identifier, + }, + value: "first_name", + }, + type_: Named( + NamedTypeAnnotation { + name: Identifier { + span: 449:455, + token: Token { + span: 449:455, + kind: Identifier, + }, + value: "Float", + }, + }, + ), + arguments: None, + directives: [], + description: None, + hack_source: None, + span: 437:447, + }, + type_: WithLocation { + location: module.js:231:234, + item: "Cat", + }, + root_fragment: None, + deprecated: Some( + PopulatedIrField( + PopulatedIrField { + key_location: module.js:23:33, + value: WithLocation { + location: module.js:34:55, + item: "Just use name instead", + }, + }, + ), + ), + semantic_non_null: Some( + ConstantDirective { + span: 437:447, + at: Token { + span: 0:0, + kind: Empty, + }, + name: Identifier { + span: 437:447, + token: Token { + span: 0:0, + kind: Empty, + }, + value: "semanticNonNull", + }, + arguments: None, + }, + ), + live: None, + location: module.js:437:447, + fragment_arguments: None, + source_hash: ResolverSourceHash( + "6f05c358daee6821384cbf6c03fcb703", + ), + type_confirmed: true, + property_lookup_name: Some( + WithLocation { + location: module.js:437:447, + item: "first_name", + }, + ), + }, + ), +) +extend type Cat { + first_name: Float @relay_resolver(fragment_name: "Cat____relay_model_instance", generated_fragment: true, inject_fragment_data: "__relay_model_instance", type_confirmed: true, has_output_type: true, import_name: "first_name", import_path: "module.js", property_lookup_name: "first_name") @resolver_source_hash(value: "6f05c358daee6821384cbf6c03fcb703") @deprecated(reason: "Just use name instead") @semanticNonNull +} + + +Type( + WeakObjectType( + WeakObjectIr { + type_name: Identifier { + span: 231:234, + token: Token { + span: 231:234, + kind: Identifier, + }, + value: "Cat", + }, + rhs_location: module.js:231:234, + description: None, + hack_source: None, + deprecated: None, + location: module.js:231:234, + implements_interfaces: [], + source_hash: ResolverSourceHash( + "6f05c358daee6821384cbf6c03fcb703", + ), + type_confirmed: true, + }, + ), +) +scalar CatModel @__RelayCustomScalar(path: "module.js", export_name: "Cat") + + +type Cat @__RelayResolverModel @RelayOutputType @__RelayWeakObject { + __relay_model_instance: CatModel! @resolver_source_hash(value: "6f05c358daee6821384cbf6c03fcb703") @unselectable(reason: "This field is intended only for Relay's internal use") +} diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/property-lookup.input b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/property-lookup.input new file mode 100644 index 0000000000000..89f302ccd2bb8 --- /dev/null +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/property-lookup.input @@ -0,0 +1,33 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +//- module.js + +/** + * @RelayResolver + */ +export type Cat = { + /** + * @gqlField + * + * This is the full name of the cat + */ + name: string, + /** + * @gqlField + */ + color: string, + /** + * @gqlField + * @deprecated Just use name instead + */ + first_name: number, + /** + * @gqlField other_name + */ + alias: number, +}; diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/resolver-functions-on-Query.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/resolver-functions-on-Query.expected index 6185f9d154df7..28ba45fe6cf49 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/resolver-functions-on-Query.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/resolver-functions-on-Query.expected @@ -62,6 +62,7 @@ Field( "38a7a82b77c64472c7bf872babfeece3", ), type_confirmed: true, + property_lookup_name: None, }, ), ) diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-non-optional-type.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-non-optional-type.expected index d4d58f898a575..5c18580a4a78b 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-non-optional-type.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-non-optional-type.expected @@ -171,6 +171,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -240,6 +241,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -322,6 +324,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -396,6 +399,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -461,6 +465,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -530,6 +535,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -599,6 +605,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -672,6 +679,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -763,6 +771,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -858,6 +867,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -944,6 +954,7 @@ Field( "b97d5d4b012e01a0c3070bd919062a36", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -984,7 +995,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "b97d5d4b012e01a0c3070bd919062a36") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-strong-object.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-strong-object.expected index fa1d85bb329fa..3593788185dff 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-strong-object.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-strong-object.expected @@ -72,6 +72,7 @@ Field( "2cd51ab90c9beb1c509ff624a8ba6609", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -112,6 +113,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "b0ce1a838dad74fce5422c930d8d9fc3") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-weak-object.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-weak-object.expected index e845d15160543..87b2e96c4aa4a 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-weak-object.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-optional-weak-object.expected @@ -73,6 +73,7 @@ Field( "1b4f4f49bebe8b72971595382a3f9b57", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -113,7 +114,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "1b4f4f49bebe8b72971595382a3f9b57") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected index f7da81a67fb75..35786ab6a6937 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected @@ -101,6 +101,7 @@ Field( "fc15c065174264428a3632fe9cf329d6", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -153,6 +154,7 @@ Field( "fc15c065174264428a3632fe9cf329d6", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -205,6 +207,7 @@ Field( "fc15c065174264428a3632fe9cf329d6", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -245,6 +248,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "fc15c065174264428a3632fe9cf329d6") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment-arguments.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment-arguments.expected index 82a9234e42270..6e1d5a961519e 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment-arguments.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment-arguments.expected @@ -113,6 +113,7 @@ Field( "d534da5736dd3e656f91a8593a50b413", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -153,6 +154,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "d534da5736dd3e656f91a8593a50b413") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment.expected index 03dc1d05543f5..f0140b089c6ad 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/root-fragment.expected @@ -88,6 +88,7 @@ Field( "0707351e18761dc811f8a249f18a13d8", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -128,6 +129,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "0707351e18761dc811f8a249f18a13d8") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/single-module.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/single-module.expected index 4fb7e58e25b52..e05bba62abaad 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/single-module.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/single-module.expected @@ -77,6 +77,7 @@ Field( "7bbe33db29d93d787719b8c25219f5a0", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -129,6 +130,7 @@ Field( "7bbe33db29d93d787719b8c25219f5a0", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -169,6 +171,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "7bbe33db29d93d787719b8c25219f5a0") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-opaque-within.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-opaque-within.expected index 35583b2f6f095..370871257f047 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-opaque-within.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-opaque-within.expected @@ -81,6 +81,7 @@ Field( "7bd696850a88d12b6ebff3689599d699", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -133,6 +134,7 @@ Field( "179d2d09d0726f713ad290a603cc35c6", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -173,6 +175,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "7bd696850a88d12b6ebff3689599d699") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-within.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-within.expected index b47abb3e9657d..1a4d2ee9e082c 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-within.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/strong-type-define-flow-within.expected @@ -81,6 +81,7 @@ Field( "8416f4ce9b514fc153597a144f614204", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -133,6 +134,7 @@ Field( "179d2d09d0726f713ad290a603cc35c6", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -173,6 +175,6 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "Cat.js", inject_fragment_data: "id") @resolver_source_hash(value: "8416f4ce9b514fc153597a144f614204") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/unsupported-type.error.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/unsupported-type.error.expected index 4df4336e0644c..b28ace5aa25de 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/unsupported-type.error.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/unsupported-type.error.expected @@ -57,7 +57,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "dbaa81766321d75c0da7fa6c70895562") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/weak-object.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/weak-object.expected index 8f0d5ff663338..fa310e1647dc5 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/weak-object.expected +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/weak-object.expected @@ -88,6 +88,7 @@ Field( "67480ced829a656aa50d7f407d9529d0", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -140,6 +141,7 @@ Field( "67480ced829a656aa50d7f407d9529d0", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -192,6 +194,7 @@ Field( "67480ced829a656aa50d7f407d9529d0", ), type_confirmed: true, + property_lookup_name: None, }, ), ) @@ -232,7 +235,7 @@ Type( ), ) type Cat @__RelayResolverModel { - id: ID! + id: ID! @__RelayResolverModelGeneratedIDField __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "67480ced829a656aa50d7f407d9529d0") @unselectable(reason: "This field is intended only for Relay's internal use") } diff --git a/compiler/crates/relay-schema-generation/tests/docblock_test.rs b/compiler/crates/relay-schema-generation/tests/docblock_test.rs index b3bf9139d1499..7c063fb841f72 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock_test.rs +++ b/compiler/crates/relay-schema-generation/tests/docblock_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<37bc46ba9cbfc9f4ef7b6b98faef30d0>> + * @generated SignedSource<> */ mod docblock; @@ -138,6 +138,13 @@ async fn primitive_types() { test_fixture(transform_fixture, file!(), "primitive-types.input", "docblock/fixtures/primitive-types.expected", input, expected).await; } +#[tokio::test] +async fn property_lookup() { + let input = include_str!("docblock/fixtures/property-lookup.input"); + let expected = include_str!("docblock/fixtures/property-lookup.expected"); + test_fixture(transform_fixture, file!(), "property-lookup.input", "docblock/fixtures/property-lookup.expected", input, expected).await; +} + #[tokio::test] async fn resolver_functions_on_query() { let input = include_str!("docblock/fixtures/resolver-functions-on-Query.input"); diff --git a/compiler/crates/relay-schema/Cargo.toml b/compiler/crates/relay-schema/Cargo.toml index 9cf972fb34e59..fd669ad8058c4 100644 --- a/compiler/crates/relay-schema/Cargo.toml +++ b/compiler/crates/relay-schema/Cargo.toml @@ -13,5 +13,5 @@ common = { path = "../common" } docblock-shared = { path = "../docblock-shared" } graphql-syntax = { path = "../graphql-syntax" } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } schema = { path = "../schema" } diff --git a/compiler/crates/relay-schema/src/relay-extensions.graphql b/compiler/crates/relay-schema/src/relay-extensions.graphql index df6d05c241d9d..8688876c82304 100644 --- a/compiler/crates/relay-schema/src/relay-extensions.graphql +++ b/compiler/crates/relay-schema/src/relay-extensions.graphql @@ -397,4 +397,4 @@ If added to a query, resolvers in that query to run at exec-time, rather than re This means the resolvers are run when the query data is requested rather than when the query is used (i.e. when the network request is made instead of at render time). """ -directive @exec_time_resolvers on QUERY +directive @exec_time_resolvers(enabledProvider: String) on QUERY diff --git a/compiler/crates/relay-test-schema/Cargo.toml b/compiler/crates/relay-test-schema/Cargo.toml index 53279f59bd1f2..915d7cba0be06 100644 --- a/compiler/crates/relay-test-schema/Cargo.toml +++ b/compiler/crates/relay-test-schema/Cargo.toml @@ -10,6 +10,6 @@ license = "MIT" [dependencies] common = { path = "../common" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } relay-schema = { path = "../relay-schema" } schema = { path = "../schema" } diff --git a/compiler/crates/relay-transforms/Cargo.toml b/compiler/crates/relay-transforms/Cargo.toml index 9db7b10355f0f..5b21c40c393eb 100644 --- a/compiler/crates/relay-transforms/Cargo.toml +++ b/compiler/crates/relay-transforms/Cargo.toml @@ -1,4 +1,4 @@ -# @generated by autocargo from //relay/oss/crates/relay-transforms:[apply_fragment_arguments_test,assignable_directive_test,assignable_fragment_spread_test,catch_directive_test,client_edges_test,client_extensions_test,declarative_connection_test,disallow_typename_on_root_test,fragment_alias_directive_test,generate_data_driven_dependency_metadata_test,generate_live_query_metadata_test,generate_relay_resolvers_operations_for_nested_objects_test,graphql-client_extensions_abstract_types-test,graphql-defer_stream-test,graphql-disallow_non_node_id_fields-test,graphql-disallow_required_on_non_null_field-test,graphql-disallow_reserved_aliases-test,graphql-disallowreadtime_features_in_mutations-test,graphql-flatten-test,graphql-generate_id_field-test,graphql-generate_typename-test,graphql-inline_fragments-test,graphql-mask-test,graphql-match-client-only-test,graphql-match-client-resolver-test,graphql-match-test,graphql-node_identifier-test,graphql-refetchable_fragment_test,graphql-skip_client_extensions-test,graphql-skip_redundant_nodes-test,graphql-skip_unreachable_nodes-test,graphql-sort_selections-test,graphql-subscription_transform-test,graphql-validate_deprecated_fields_test,graphql-validate_fragment_alias_conflict-test,graphql-validate_module_names-test,graphql-validate_relay_directives-test,graphql-validate_required_arguments_test,graphql-validate_server_only_directives-test,graphql-validate_unused_variables-test,inline_data_fragment_test,provided-variable-fragment-transform-test,relay-actor-change-test,relay-transforms,relay_resolvers_abstract_types_test,relay_resolvers_test,relay_test_operation_test,required_directive_test,skip_unused_variables_test,transform_connections_test,updatable_directive_test,updatable_fragment_spread_test,validate_connections_schema_test,validate_connections_test,validate_global_variable_names_test,validate_global_variables-test,validate_no_double_underscore_alias_test,validate_no_unselectable_selections_test,validate_static_args] +# @generated by autocargo from //relay/oss/crates/relay-transforms:[apply_fragment_arguments_test,assignable_directive_test,assignable_fragment_spread_test,catch_directive_test,client_edges_test,client_extensions_test,declarative_connection_test,disallow_typename_on_root_test,fragment_alias_directive_test,generate_data_driven_dependency_metadata_test,generate_live_query_metadata_test,generate_relay_resolvers_operations_for_nested_objects_test,graphql-client_extensions_abstract_types-test,graphql-defer_stream-test,graphql-disallow_non_node_id_fields-test,graphql-disallow_required_on_non_null_field-test,graphql-disallow_reserved_aliases-test,graphql-disallowreadtime_features_in_mutations-test,graphql-flatten-test,graphql-generate_id_field-test,graphql-generate_typename-test,graphql-inline_fragments-test,graphql-mask-test,graphql-match-client-only-test,graphql-match-client-resolver-test,graphql-match-test,graphql-node_identifier-test,graphql-refetchable_fragment_test,graphql-skip_client_extensions-test,graphql-skip_redundant_nodes-test,graphql-skip_unreachable_nodes-test,graphql-sort_selections-test,graphql-subscription_transform-test,graphql-validate_deprecated_fields_test,graphql-validate_fragment_alias_conflict-test,graphql-validate_module_names-test,graphql-validate_relay_directives-test,graphql-validate_required_arguments_test,graphql-validate_server_only_directives-test,graphql-validate_unused_variables-test,inline_data_fragment_test,provided-variable-fragment-transform-test,relay-actor-change-test,relay-transforms,relay_resolvers_abstract_types_test,relay_resolvers_test,relay_test_operation_test,required_directive_test,skip_unused_variables_test,transform_connections_test,updatable_directive_test,updatable_fragment_spread_test,validate-client-schema-extensions-use-catch-test,validate_connections_schema_test,validate_connections_test,validate_global_variable_names_test,validate_global_variables-test,validate_no_double_underscore_alias_test,validate_no_unselectable_selections_test,validate_static_args] [package] name = "relay-transforms" @@ -136,16 +136,16 @@ graphql-syntax = { path = "../graphql-syntax" } graphql-text-printer = { path = "../graphql-text-printer" } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } intern = { path = "../intern" } -itertools = "0.13.0" -lazy_static = "1.4" +itertools = "0.14.0" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } parking_lot = { version = "0.12.1", features = ["send_guard"] } -regex = "1.9.2" +regex = "1.11.1" relay-config = { path = "../relay-config" } relay-schema = { path = "../relay-schema" } -rustc-hash = "1.1.0" +rustc-hash = "2.1.0" schema = { path = "../schema" } serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] fixture-tests = { path = "../fixture-tests" } diff --git a/compiler/crates/relay-transforms/src/apply_fragment_arguments.rs b/compiler/crates/relay-transforms/src/apply_fragment_arguments.rs index 3ad1f666e900e..8dafc847be9c0 100644 --- a/compiler/crates/relay-transforms/src/apply_fragment_arguments.rs +++ b/compiler/crates/relay-transforms/src/apply_fragment_arguments.rs @@ -29,7 +29,6 @@ use graphql_ir::FragmentDefinition; use graphql_ir::FragmentDefinitionName; use graphql_ir::FragmentDefinitionNameMap; use graphql_ir::FragmentDefinitionNameSet; -use graphql_ir::FragmentSignature; use graphql_ir::FragmentSpread; use graphql_ir::InlineFragment; use graphql_ir::OperationDefinition; @@ -47,6 +46,7 @@ use graphql_ir::VariableDefinition; use graphql_ir::VariableName; use graphql_syntax::OperationKind; use intern::string_key::Intern; +use intern::string_key::StringKey; use intern::string_key::StringKeyIndexMap; use intern::string_key::StringKeyMap; use itertools::Itertools; @@ -169,7 +169,7 @@ struct ApplyFragmentArgumentsTransform<'flags, 'program, 'base_fragments> { split_operations: StringKeyMap<(Option, ProvidedVariablesMap)>, } -impl Transformer for ApplyFragmentArgumentsTransform<'_, '_, '_> { +impl Transformer<'_> for ApplyFragmentArgumentsTransform<'_, '_, '_> { const NAME: &'static str = "ApplyFragmentArgumentsTransform"; const VISIT_ARGUMENTS: bool = true; const VISIT_DIRECTIVES: bool = true; @@ -190,7 +190,22 @@ impl Transformer for ApplyFragmentArgumentsTransform<'_, '_, '_> { // this transform does not add the SplitOperation directive, so this // should be equal to checking whether the result is a split operation self.provided_variables.clear(); - transform_result + + match transform_result { + Transformed::Keep => Transformed::Keep, + Transformed::Replace(new_operation) => Transformed::Replace(new_operation), + Transformed::Delete => { + self.errors.push(Diagnostic::error( + ValidationMessage::EmptySelectionsInDocument { + document: "query", + name: operation.name.item.0, + }, + operation.name.location, + )); + + Transformed::Delete + } + } } else { let mut add_provided_variables = |new_operation: &mut OperationDefinition| { new_operation.variable_definitions.append( @@ -211,7 +226,17 @@ impl Transformer for ApplyFragmentArgumentsTransform<'_, '_, '_> { add_provided_variables(&mut new_operation); Transformed::Replace(new_operation) } - Transformed::Delete => Transformed::Delete, + Transformed::Delete => { + self.errors.push(Diagnostic::error( + ValidationMessage::EmptySelectionsInDocument { + document: "query", + name: operation.name.item.0, + }, + operation.name.location, + )); + + Transformed::Delete + } } } } @@ -299,12 +324,7 @@ impl Transformer for ApplyFragmentArgumentsTransform<'_, '_, '_> { fragment.name.location, FragmentDefinitionName(normalization_name), ), - signature: Some(FragmentSignature { - name: fragment.name, - variable_definitions: fragment.variable_definitions.clone(), - type_condition: fragment.type_condition, - directives: fragment.directives.clone(), - }), + signature: Some(fragment.as_ref().into()), })); // If the fragment type is abstract, we need to ensure that it's only evaluated at runtime if the // type of the object matches the fragment's type condition. Rather than reimplement type refinement @@ -331,12 +351,7 @@ impl Transformer for ApplyFragmentArgumentsTransform<'_, '_, '_> { fragment: applied_fragment.name, arguments: Vec::new(), directives, - signature: Some(FragmentSignature { - name: applied_fragment.name, - variable_definitions: applied_fragment.variable_definitions.clone(), - type_condition: applied_fragment.type_condition, - directives: applied_fragment.directives.clone(), - }), + signature: Some(applied_fragment.as_ref().into()), }))) } else { Transformed::Delete @@ -741,4 +756,14 @@ enum ValidationMessage { ProvidedVariableIncompatibleWithArguments { original_definition_name: VariableName, }, + #[error( + "After applying transforms to the {document} `{name}` selections of \ + the `{name}` that would be sent to the server are empty. \ + This is likely due to the use of `@skip`/`@include` directives with \ + constant values that remove all selections in the {document}. " + )] + EmptySelectionsInDocument { + name: StringKey, + document: &'static str, + }, } diff --git a/compiler/crates/relay-transforms/src/assignable_fragment_spread/annotate_updatable_fragment_spreads.rs b/compiler/crates/relay-transforms/src/assignable_fragment_spread/annotate_updatable_fragment_spreads.rs index 7679638e2d095..351b665446bc2 100644 --- a/compiler/crates/relay-transforms/src/assignable_fragment_spread/annotate_updatable_fragment_spreads.rs +++ b/compiler/crates/relay-transforms/src/assignable_fragment_spread/annotate_updatable_fragment_spreads.rs @@ -39,7 +39,7 @@ struct AnnotateUpdatableFragmentSpreads<'s> { program: &'s Program, } -impl<'s> Transformer for AnnotateUpdatableFragmentSpreads<'s> { +impl Transformer<'_> for AnnotateUpdatableFragmentSpreads<'_> { const NAME: &'static str = "AnnotateUpdatableFragmentSpreads"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/assignable_fragment_spread/replace_updatable_fragment_spreads.rs b/compiler/crates/relay-transforms/src/assignable_fragment_spread/replace_updatable_fragment_spreads.rs index de9a2df3253b1..5ff7e837af240 100644 --- a/compiler/crates/relay-transforms/src/assignable_fragment_spread/replace_updatable_fragment_spreads.rs +++ b/compiler/crates/relay-transforms/src/assignable_fragment_spread/replace_updatable_fragment_spreads.rs @@ -31,7 +31,7 @@ struct ReplaceAssignableFragmentSpreads<'s> { program: &'s Program, } -impl<'s> Transformer for ReplaceAssignableFragmentSpreads<'s> { +impl Transformer<'_> for ReplaceAssignableFragmentSpreads<'_> { const NAME: &'static str = "ReplaceAssignableFragmentSpreads"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_regular_queries.rs b/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_regular_queries.rs index 1edaf971de21b..ce8800c05d653 100644 --- a/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_regular_queries.rs +++ b/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_regular_queries.rs @@ -31,6 +31,7 @@ use super::ensure_discriminated_union_is_created; use super::errors::ValidationMessage; use super::ASSIGNABLE_DIRECTIVE; use super::UPDATABLE_DIRECTIVE; +use crate::fragment_alias_directive::FRAGMENT_DANGEROUSLY_UNALIAS_DIRECTIVE_NAME; pub fn transform_assignable_fragment_spreads_in_regular_queries( program: &Program, @@ -58,7 +59,7 @@ struct AssignableFragmentSpread<'s> { path: Vec, } -impl<'s> AssignableFragmentSpread<'s> { +impl AssignableFragmentSpread<'_> { /// 1. Validate that the assignable fragment does not have @skip/@defer, and /// is not within an inline fragment with directives, and is nested in a linked field /// 2. Mark the enclosing linked field as containing an assignable fragment spread. @@ -137,7 +138,7 @@ enum ValidGeneratedFlowType { Any, } -impl<'s> Transformer for AssignableFragmentSpread<'s> { +impl Transformer<'_> for AssignableFragmentSpread<'_> { const NAME: &'static str = "AssignableFragmentTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -208,8 +209,14 @@ impl<'s> Transformer for AssignableFragmentSpread<'s> { return Transformed::Keep; } + let dissallowed_directives = fragment_spread + .directives + .iter() + .filter(|directive| directive.name.item != *FRAGMENT_DANGEROUSLY_UNALIAS_DIRECTIVE_NAME) + .collect::>(); + // Assignable fragments cannot have directives, but we error only on the first one - if let Some(directive) = fragment_spread.directives.first() { + if let Some(directive) = dissallowed_directives.first() { self.errors.push(Diagnostic::error( ValidationMessage::AssignableFragmentSpreadNoOtherDirectives { disallowed_directive_name: directive.name.item.0, diff --git a/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_updatable_queries.rs b/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_updatable_queries.rs index 0c258d90f3339..e4fca52a21f78 100644 --- a/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_updatable_queries.rs +++ b/compiler/crates/relay-transforms/src/assignable_fragment_spread/transform_assignable_fragment_spreads_in_updatable_queries.rs @@ -71,7 +71,7 @@ struct AssignableFragmentSpreadForUpdatable<'s> { program: &'s Program, } -impl<'s> Transformer for AssignableFragmentSpreadForUpdatable<'s> { +impl Transformer<'_> for AssignableFragmentSpreadForUpdatable<'_> { const NAME: &'static str = "AssignableFragmentTransformForUpdatable"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_assignable_directive.rs b/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_assignable_directive.rs index 5d99b1ae552b1..4d7fca006c087 100644 --- a/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_assignable_directive.rs +++ b/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_assignable_directive.rs @@ -36,7 +36,7 @@ struct AssignableDirective<'a> { program: &'a Program, } -impl<'a> Validator for AssignableDirective<'a> { +impl Validator for AssignableDirective<'_> { const NAME: &'static str = "AssignableDirective"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_directive.rs b/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_directive.rs index 1ac3160bb579f..7b289ad3443b3 100644 --- a/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_directive.rs +++ b/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_directive.rs @@ -35,10 +35,12 @@ use schema::Schema; use super::ValidationMessage; use super::ASSIGNABLE_DIRECTIVE; use super::UPDATABLE_DIRECTIVE; +use crate::fragment_alias_directive::FRAGMENT_DANGEROUSLY_UNALIAS_DIRECTIVE_NAME; lazy_static! { static ref ALLOW_LISTED_DIRECTIVES: Vec = vec![ *UPDATABLE_DIRECTIVE, + *FRAGMENT_DANGEROUSLY_UNALIAS_DIRECTIVE_NAME, // TODO have a global list of directives...? DirectiveName("fb_owner".intern()), ]; @@ -266,7 +268,7 @@ impl<'a> UpdatableDirective<'a> { } } -impl<'a> Validator for UpdatableDirective<'a> { +impl Validator for UpdatableDirective<'_> { const NAME: &'static str = "UpdatableDirective"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_fragment_spread.rs b/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_fragment_spread.rs index fc9c1372068f8..541fcd763c48d 100644 --- a/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_fragment_spread.rs +++ b/compiler/crates/relay-transforms/src/assignable_fragment_spread/validate_updatable_fragment_spread.rs @@ -21,6 +21,7 @@ use schema::TypeReference; use super::ensure_discriminated_union_is_created; use super::ValidationMessage; +use crate::fragment_alias_directive::FRAGMENT_DANGEROUSLY_UNALIAS_DIRECTIVE_NAME; use crate::UPDATABLE_DIRECTIVE; pub fn validate_updatable_fragment_spread(program: &Program) -> DiagnosticsResult<()> { @@ -56,7 +57,7 @@ struct UpdatableFragmentSpread<'a> { path: Vec, } -impl<'a> UpdatableFragmentSpread<'a> { +impl UpdatableFragmentSpread<'_> { /// Validate many conditions for spreads of updatable fragments: /// * the fragment spread contains no directives /// * there is no @if or @skip between the linked field and the fragment spread @@ -88,10 +89,15 @@ impl<'a> UpdatableFragmentSpread<'a> { ) -> DiagnosticsResult<()> { let mut errors = vec![]; - if !fragment_spread.directives.is_empty() { + let invalid_directive = fragment_spread + .directives + .iter() + .find(|directive| directive.name.item != *FRAGMENT_DANGEROUSLY_UNALIAS_DIRECTIVE_NAME); + + if let Some(directive) = invalid_directive { errors.push(Diagnostic::error( ValidationMessage::UpdatableFragmentSpreadNoDirectives, - fragment_spread.fragment.location, + directive.location, )); } @@ -183,7 +189,7 @@ impl<'a> UpdatableFragmentSpread<'a> { } } -impl<'a> Validator for UpdatableFragmentSpread<'a> { +impl Validator for UpdatableFragmentSpread<'_> { const NAME: &'static str = "UpdatableFragmentSpread"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/catch_directive.rs b/compiler/crates/relay-transforms/src/catch_directive.rs index d188f938317a5..aa86710134afd 100644 --- a/compiler/crates/relay-transforms/src/catch_directive.rs +++ b/compiler/crates/relay-transforms/src/catch_directive.rs @@ -137,7 +137,7 @@ impl<'program> CatchDirective<'program> { } } -impl<'s> Transformer for CatchDirective<'s> { +impl Transformer<'_> for CatchDirective<'_> { const NAME: &'static str = "CatchDirectiveTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/client_edges.rs b/compiler/crates/relay-transforms/src/client_edges.rs index 384f62ada4d92..a93326d177559 100644 --- a/compiler/crates/relay-transforms/src/client_edges.rs +++ b/compiler/crates/relay-transforms/src/client_edges.rs @@ -51,6 +51,7 @@ use schema::Schema; use schema::Type; use super::ValidationMessageWithData; +use crate::match_::MATCH_CONSTANTS; use crate::refetchable_fragment::RefetchableFragment; use crate::refetchable_fragment::REFETCHABLE_NAME; use crate::relay_resolvers::get_bool_argument_is_true; @@ -103,7 +104,7 @@ associated_data_impl!(ClientEdgeGeneratedQueryMetadataDirective); pub struct ClientEdgeMetadata<'a> { /// The field which defines the graph relationship (currently always a Resolver) - pub backing_field: Selection, + pub backing_field: &'a Selection, /// Models the client edge field and its selections pub linked_field: &'a LinkedField, /// Additional metadata about the client edge @@ -132,14 +133,10 @@ impl<'a> ClientEdgeMetadata<'a> { fragment.selections.len() == 2, "Expected Client Edge inline fragment to have exactly two selections. This is a bug in the Relay compiler." ); - let mut backing_field = fragment - .selections.first() - .expect("Client Edge inline fragments have exactly two selections").clone(); - let backing_field_directives = backing_field.directives().iter().filter(|directive| - directive.name.item != RequiredMetadataDirective::directive_name() - ).cloned().collect(); - backing_field.set_directives(backing_field_directives); + let backing_field = fragment + .selections.first() + .expect("Client Edge inline fragments have exactly two selections"); let linked_field = match fragment.selections.get(1) { Some(Selection::LinkedField(linked_field)) => linked_field, @@ -317,6 +314,7 @@ impl<'program, 'pc> ClientEdgesTransform<'program, 'pc> { *REQUIRED_DIRECTIVE_NAME, *CHILDREN_CAN_BUBBLE_METADATA_KEY, RequiredMetadataDirective::directive_name(), + MATCH_CONSTANTS.match_directive_name, ]; let other_directives = directives @@ -488,6 +486,12 @@ impl<'program, 'pc> ClientEdgesTransform<'program, 'pc> { waterfall_directive: Option<&Directive>, selections: Vec, ) -> ClientEdgeMetadataDirective { + if field_type.type_.is_list() { + self.errors.push(Diagnostic::error( + ValidationMessage::ClientEdgeToServerObjectList, + field_type.name.location, + )); + } // Client Edges to server objects must be annotated with @waterfall if waterfall_directive.is_none() { self.errors.push(Diagnostic::error_with_data( @@ -606,7 +610,20 @@ fn create_inline_fragment_for_client_edge( } let transformed_field = Arc::new(LinkedField { + selections: selections.clone(), + ..field.clone() + }); + + let backing_field_directives = field + .directives() + .iter() + .filter(|directive| directive.name.item != RequiredMetadataDirective::directive_name()) + .cloned() + .collect(); + + let backing_field = Arc::new(LinkedField { selections, + directives: backing_field_directives, ..field.clone() }); @@ -615,14 +632,14 @@ fn create_inline_fragment_for_client_edge( directives: inline_fragment_directives, selections: vec![ // NOTE: This creates 2^H selecitons where H is the depth of nested client edges + Selection::LinkedField(Arc::clone(&backing_field)), Selection::LinkedField(Arc::clone(&transformed_field)), - Selection::LinkedField(transformed_field), ], spread_location: Location::generated(), } } -impl Transformer for ClientEdgesTransform<'_, '_> { +impl Transformer<'_> for ClientEdgesTransform<'_, '_> { const NAME: &'static str = "ClientEdgesTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -716,7 +733,7 @@ pub fn remove_client_edge_selections(program: &Program) -> DiagnosticsResult for ClientEdgesCleanupTransform { const NAME: &'static str = "ClientEdgesCleanupTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -727,7 +744,7 @@ impl Transformer for ClientEdgesCleanupTransform { let new_selection = metadata.backing_field; Transformed::Replace( - self.transform_selection(&new_selection) + self.transform_selection(new_selection) .unwrap_or_else(|| new_selection.clone()), ) } diff --git a/compiler/crates/relay-transforms/src/client_extensions.rs b/compiler/crates/relay-transforms/src/client_extensions.rs index 0f888de844799..7ea037532537d 100644 --- a/compiler/crates/relay-transforms/src/client_extensions.rs +++ b/compiler/crates/relay-transforms/src/client_extensions.rs @@ -9,7 +9,6 @@ use std::sync::Arc; use common::DirectiveName; use common::Location; -use common::PointerAddress; use common::WithLocation; use fnv::FnvHashMap; use graphql_ir::Directive; @@ -37,7 +36,7 @@ pub fn client_extensions(program: &Program) -> Program { .replace_or_else(|| program.clone()) } -type Seen = FnvHashMap>; +type Seen<'a> = FnvHashMap<&'a Selection, Transformed>; lazy_static! { pub static ref CLIENT_EXTENSION_DIRECTIVE_NAME: DirectiveName = @@ -46,7 +45,7 @@ lazy_static! { struct ClientExtensionsTransform<'program> { program: &'program Program, - seen: Seen, + seen: Seen<'program>, } impl<'program> ClientExtensionsTransform<'program> { @@ -60,7 +59,7 @@ impl<'program> ClientExtensionsTransform<'program> { fn transform_client_edge( &mut self, fragment: &InlineFragment, - metadata: ClientEdgeMetadata<'_>, + metadata: ClientEdgeMetadata<'program>, ) -> Transformed { // Backing field should always be a RelayResolver. We can't wrap a // resolver. If its a scalar (no fragment) we don't need to wrap @@ -74,7 +73,7 @@ impl<'program> ClientExtensionsTransform<'program> { // fields of the client edge get wrapped with a client extension inline // fragment or deleted. let backing_field = self - .transform_selection(&metadata.backing_field) + .transform_selection(metadata.backing_field) .unwrap_or_else(|| metadata.backing_field.clone()); let selections = self @@ -88,14 +87,14 @@ impl<'program> ClientExtensionsTransform<'program> { } } -impl Transformer for ClientExtensionsTransform<'_> { +impl<'a> Transformer<'a> for ClientExtensionsTransform<'a> { const NAME: &'static str = "ClientExtensionsTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; fn transform_selections( &mut self, - selections: &[Selection], + selections: &'a [Selection], ) -> TransformedValue> { if selections.is_empty() { return TransformedValue::Keep; @@ -152,19 +151,20 @@ impl Transformer for ClientExtensionsTransform<'_> { } } - fn transform_selection(&mut self, selection: &Selection) -> Transformed { - let key = PointerAddress::new(selection); - if let Some(prev) = self.seen.get(&key) { - prev.clone() - } else { - self.seen.insert(key, Transformed::Keep); - let result = self.default_transform_selection(selection); - self.seen.insert(key, result.clone()); - result + fn transform_selection(&mut self, selection: &'a Selection) -> Transformed { + if let Some(prev) = self.seen.get(selection) { + return prev.clone(); } + + let result = self.default_transform_selection(selection); + self.seen.insert(selection, result.clone()); + result } - fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed { + fn transform_inline_fragment( + &mut self, + fragment: &'a InlineFragment, + ) -> Transformed { // Client Edges are modeled in the IR as inline fragments. If we // traverse into those fragments, and pull its contents out into a // separate inline fragment (without this directive) we will have lost @@ -183,7 +183,7 @@ impl Transformer for ClientExtensionsTransform<'_> { self.default_transform_inline_fragment(fragment) } - fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed { + fn transform_linked_field(&mut self, field: &'a LinkedField) -> Transformed { if self .program .schema diff --git a/compiler/crates/relay-transforms/src/client_extensions_abstract_types.rs b/compiler/crates/relay-transforms/src/client_extensions_abstract_types.rs index 754f832c6e99e..caae4e0875092 100644 --- a/compiler/crates/relay-transforms/src/client_extensions_abstract_types.rs +++ b/compiler/crates/relay-transforms/src/client_extensions_abstract_types.rs @@ -174,7 +174,7 @@ impl<'program> ClientExtensionsAbstactTypesTransform<'program> { } } -impl Transformer for ClientExtensionsAbstactTypesTransform<'_> { +impl Transformer<'_> for ClientExtensionsAbstactTypesTransform<'_> { const NAME: &'static str = "ClientExtensionsAbstactTypesTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/debug_transform.rs b/compiler/crates/relay-transforms/src/debug_transform.rs index 06f0e3d5714b3..9f8d01ee98fb2 100644 --- a/compiler/crates/relay-transforms/src/debug_transform.rs +++ b/compiler/crates/relay-transforms/src/debug_transform.rs @@ -40,7 +40,7 @@ const PRINTER_OPTIONS: PrinterOptions = PrinterOptions { debug_directive_data: false, }; -impl Transformer for DebugTransform { +impl Transformer<'_> for DebugTransform { const NAME: &'static str = "DebugTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/declarative_connection.rs b/compiler/crates/relay-transforms/src/declarative_connection.rs index 012e31ff8cc4e..da5ce52c67b42 100644 --- a/compiler/crates/relay-transforms/src/declarative_connection.rs +++ b/compiler/crates/relay-transforms/src/declarative_connection.rs @@ -102,7 +102,7 @@ impl<'a> DeclarativeConnectionMutationTransform<'a> { } } -impl Transformer for DeclarativeConnectionMutationTransform<'_> { +impl Transformer<'_> for DeclarativeConnectionMutationTransform<'_> { const NAME: &'static str = "DeclarativeConnectionMutationTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/defer_stream.rs b/compiler/crates/relay-transforms/src/defer_stream.rs index 825c527b591cc..7d3e5058a200c 100644 --- a/compiler/crates/relay-transforms/src/defer_stream.rs +++ b/compiler/crates/relay-transforms/src/defer_stream.rs @@ -275,7 +275,7 @@ impl DeferStreamTransform<'_> { } } -impl<'s> Transformer for DeferStreamTransform<'s> { +impl Transformer<'_> for DeferStreamTransform<'_> { const NAME: &'static str = "DeferStreamTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/errors.rs b/compiler/crates/relay-transforms/src/errors.rs index 57b83a7a16106..6f97aaca04f0a 100644 --- a/compiler/crates/relay-transforms/src/errors.rs +++ b/compiler/crates/relay-transforms/src/errors.rs @@ -131,6 +131,12 @@ pub enum ValidationMessage { name: StringKey, type_name: ObjectName, }, + + #[error( + "Unexpected Relay Resolver returning plual edge to type defined on the server. Relay Resolvers do not curretly support returning plural edges to server types. As a work around, consider defining a plural edge to a client type which has a singular edge to the server type." + )] + ClientEdgeToServerObjectList, + #[error("Invalid directive combination. @alias may not be combined with other directives.")] FragmentAliasIncompatibleDirective, diff --git a/compiler/crates/relay-transforms/src/fragment_alias_directive.rs b/compiler/crates/relay-transforms/src/fragment_alias_directive.rs index d22674a60c2ae..7f380dc43fc43 100644 --- a/compiler/crates/relay-transforms/src/fragment_alias_directive.rs +++ b/compiler/crates/relay-transforms/src/fragment_alias_directive.rs @@ -79,7 +79,7 @@ pub fn remove_aliased_inline_fragments(program: &Program) -> Program { struct AliasedInlineFragmentRemovalTransform {} -impl Transformer for AliasedInlineFragmentRemovalTransform { +impl Transformer<'_> for AliasedInlineFragmentRemovalTransform { const NAME: &'static str = "AliasedInlineFragmentRemovalTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -257,7 +257,7 @@ impl<'program> FragmentAliasTransform<'program> { } } -impl Transformer for FragmentAliasTransform<'_> { +impl Transformer<'_> for FragmentAliasTransform<'_> { const NAME: &'static str = "NamedFragmentSpreadsTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/generate_data_driven_dependency_metadata.rs b/compiler/crates/relay-transforms/src/generate_data_driven_dependency_metadata.rs index 8277252b7789f..a160f9118ce26 100644 --- a/compiler/crates/relay-transforms/src/generate_data_driven_dependency_metadata.rs +++ b/compiler/crates/relay-transforms/src/generate_data_driven_dependency_metadata.rs @@ -228,7 +228,7 @@ struct ProcessingItem<'a> { selections: &'a [Selection], } -impl<'s> Transformer for GenerateDataDrivenDependencyMetadata<'s> { +impl Transformer<'_> for GenerateDataDrivenDependencyMetadata<'_> { const NAME: &'static str = "GenerateDataDrivenDependencyMetadata"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/generate_id_field.rs b/compiler/crates/relay-transforms/src/generate_id_field.rs index 5d54604348ff7..0b2b5252b811d 100644 --- a/compiler/crates/relay-transforms/src/generate_id_field.rs +++ b/compiler/crates/relay-transforms/src/generate_id_field.rs @@ -52,7 +52,7 @@ struct NodeInterface { id_field: FieldID, } -impl<'s> Transformer for GenerateIDFieldTransform<'s> { +impl Transformer<'_> for GenerateIDFieldTransform<'_> { const NAME: &'static str = "GenerateIDFieldTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/generate_live_query_metadata.rs b/compiler/crates/relay-transforms/src/generate_live_query_metadata.rs index 608eccec06f39..58d95407be44e 100644 --- a/compiler/crates/relay-transforms/src/generate_live_query_metadata.rs +++ b/compiler/crates/relay-transforms/src/generate_live_query_metadata.rs @@ -57,7 +57,7 @@ struct GenerateLiveQueryMetadata { errors: Vec, } -impl Transformer for GenerateLiveQueryMetadata { +impl Transformer<'_> for GenerateLiveQueryMetadata { const NAME: &'static str = "GenerateLiveQueryMetadata"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/generate_typename.rs b/compiler/crates/relay-transforms/src/generate_typename.rs index b78e3241a2f25..f3b88b9a7a3f7 100644 --- a/compiler/crates/relay-transforms/src/generate_typename.rs +++ b/compiler/crates/relay-transforms/src/generate_typename.rs @@ -9,7 +9,6 @@ use std::sync::Arc; use common::DirectiveName; use common::Location; -use common::PointerAddress; use common::WithLocation; use fnv::FnvHashMap; use graphql_ir::Directive; @@ -47,14 +46,11 @@ pub fn generate_typename(program: &Program, is_for_codegen: bool) -> Program { .replace_or_else(|| program.clone()) } -// Note on correctness: the PointerAddress here is calculated from addresses of the input -// context. Because those value are still referenced, that memory cannot be freed/ -// reused for the lifetime of the transform. -type Seen = FnvHashMap>; +type Seen<'a> = FnvHashMap<&'a InlineFragment, Transformed>; struct GenerateTypenameTransform<'s> { program: &'s Program, - seen: Seen, + seen: Seen<'s>, is_for_codegen: bool, parent_type: Option, } @@ -70,14 +66,14 @@ impl<'s> GenerateTypenameTransform<'s> { } } -impl<'s> Transformer for GenerateTypenameTransform<'s> { +impl<'s> Transformer<'s> for GenerateTypenameTransform<'s> { const NAME: &'static str = "GenerateTypenameTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; fn transform_operation( &mut self, - operation: &OperationDefinition, + operation: &'s OperationDefinition, ) -> Transformed { self.parent_type = Some(operation.type_); self.default_transform_operation(operation) @@ -85,7 +81,7 @@ impl<'s> Transformer for GenerateTypenameTransform<'s> { fn transform_fragment( &mut self, - fragment: &FragmentDefinition, + fragment: &'s FragmentDefinition, ) -> Transformed { self.parent_type = Some(fragment.type_condition); let schema = &self.program.schema; @@ -115,7 +111,7 @@ impl<'s> Transformer for GenerateTypenameTransform<'s> { } } - fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed { + fn transform_linked_field(&mut self, field: &'s LinkedField) -> Transformed { let schema = &self.program.schema; let field_definition = schema.field(field.definition.item); let parent_type = self.parent_type; @@ -154,12 +150,14 @@ impl<'s> Transformer for GenerateTypenameTransform<'s> { } } - fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed { - let key = PointerAddress::new(fragment); - if let Some(prev) = self.seen.get(&key) { + fn transform_inline_fragment( + &mut self, + fragment: &'s InlineFragment, + ) -> Transformed { + if let Some(prev) = self.seen.get(fragment) { return prev.clone(); } - self.seen.insert(key, Transformed::Delete); + self.seen.insert(fragment, Transformed::Delete); let parent_type = self.parent_type; if fragment.type_condition.is_some() { self.parent_type = fragment.type_condition; @@ -204,7 +202,7 @@ impl<'s> Transformer for GenerateTypenameTransform<'s> { }))) } }; - self.seen.insert(key, result.clone()); + self.seen.insert(fragment, result.clone()); result } diff --git a/compiler/crates/relay-transforms/src/handle_fields/handle_field_transform.rs b/compiler/crates/relay-transforms/src/handle_fields/handle_field_transform.rs index 27c997c5950a6..88312f059f337 100644 --- a/compiler/crates/relay-transforms/src/handle_fields/handle_field_transform.rs +++ b/compiler/crates/relay-transforms/src/handle_fields/handle_field_transform.rs @@ -58,7 +58,7 @@ impl HandleFieldTransform { } } -impl Transformer for HandleFieldTransform { +impl Transformer<'_> for HandleFieldTransform { const NAME: &'static str = "HandleFieldTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/handle_fields/handle_field_util.rs b/compiler/crates/relay-transforms/src/handle_fields/handle_field_util.rs index b839ecc2892fe..3b1d642f4a12c 100644 --- a/compiler/crates/relay-transforms/src/handle_fields/handle_field_util.rs +++ b/compiler/crates/relay-transforms/src/handle_fields/handle_field_util.rs @@ -46,8 +46,8 @@ pub struct HandleFieldDirectiveValues { } /// We have two handler keys, "handler" in connection, and "handle" in everywhere else -/// Speicific helpers are created separately for connection - +/// Specific helpers are created separately for connection +/// /// Helper to extract handle field arguments that are present /// on the directive, without any validation or assumption of /// correctness of values. diff --git a/compiler/crates/relay-transforms/src/inline_data_fragment.rs b/compiler/crates/relay-transforms/src/inline_data_fragment.rs index 63dae3c9929a4..f2d0683e4a906 100644 --- a/compiler/crates/relay-transforms/src/inline_data_fragment.rs +++ b/compiler/crates/relay-transforms/src/inline_data_fragment.rs @@ -97,7 +97,7 @@ pub struct InlineDirectiveMetadata { } associated_data_impl!(InlineDirectiveMetadata); -impl<'s> Transformer for InlineDataFragmentsTransform<'s> { +impl Transformer<'_> for InlineDataFragmentsTransform<'_> { const NAME: &'static str = "InlineDataFragmentsTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/inline_fragments.rs b/compiler/crates/relay-transforms/src/inline_fragments.rs index 9a9382dac3094..02f6854401044 100644 --- a/compiler/crates/relay-transforms/src/inline_fragments.rs +++ b/compiler/crates/relay-transforms/src/inline_fragments.rs @@ -119,7 +119,7 @@ impl<'s> InlineFragmentsTransform<'s> { } } -impl<'s> Transformer for InlineFragmentsTransform<'s> { +impl Transformer<'_> for InlineFragmentsTransform<'_> { const NAME: &'static str = "InlineFragmentsTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/lib.rs b/compiler/crates/relay-transforms/src/lib.rs index 580be9e785a5f..24afbe186d7e0 100644 --- a/compiler/crates/relay-transforms/src/lib.rs +++ b/compiler/crates/relay-transforms/src/lib.rs @@ -199,6 +199,7 @@ pub use rescript_relay_generate_typename::rescript_relay_generate_typename; pub use rescript_relay_inline_codesplit::rescript_relay_inline_codesplit; pub use rescript_relay_transform_codesplit::rescript_relay_transform_codesplit; pub use required_directive::THROW_ACTION; +pub use root_variables::VariableMapEntry; pub use skip_client_directives::skip_client_directives; pub use skip_client_extensions::skip_client_extensions; pub use skip_null_arguments_transform::skip_null_arguments_transform; diff --git a/compiler/crates/relay-transforms/src/mask.rs b/compiler/crates/relay-transforms/src/mask.rs index 1739c730b8a5b..77f43880734fb 100644 --- a/compiler/crates/relay-transforms/src/mask.rs +++ b/compiler/crates/relay-transforms/src/mask.rs @@ -80,7 +80,7 @@ impl<'s> Mask<'s> { } } -impl<'s> Transformer for Mask<'s> { +impl Transformer<'_> for Mask<'_> { const NAME: &'static str = "MaskTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/match_/hash_supported_argument.rs b/compiler/crates/relay-transforms/src/match_/hash_supported_argument.rs index 1c7ad5e55cab0..6c0840bb7be02 100644 --- a/compiler/crates/relay-transforms/src/match_/hash_supported_argument.rs +++ b/compiler/crates/relay-transforms/src/match_/hash_supported_argument.rs @@ -45,7 +45,7 @@ struct HashSupportedArgumentTransform<'a> { errors: Vec, } -impl<'a> Transformer for HashSupportedArgumentTransform<'a> { +impl Transformer<'_> for HashSupportedArgumentTransform<'_> { const NAME: &'static str = "HashSupportedArgumentTransform"; const VISIT_ARGUMENTS: bool = false; @@ -110,7 +110,7 @@ impl<'a> Transformer for HashSupportedArgumentTransform<'a> { } } -impl<'a> HashSupportedArgumentTransform<'a> { +impl HashSupportedArgumentTransform<'_> { /// Returns true iff the field is supplied with a `supported` arg and that /// arg has a type of `[string]` (potentially non-nullable somewhere). fn has_match_supported_arg(&self, field: &LinkedField) -> bool { diff --git a/compiler/crates/relay-transforms/src/match_/match_transform.rs b/compiler/crates/relay-transforms/src/match_/match_transform.rs index 6aad76daece78..42efcbbacc6fe 100644 --- a/compiler/crates/relay-transforms/src/match_/match_transform.rs +++ b/compiler/crates/relay-transforms/src/match_/match_transform.rs @@ -62,7 +62,7 @@ use crate::fragment_alias_directive::FRAGMENT_ALIAS_DIRECTIVE_NAME; use crate::match_::MATCH_CONSTANTS; use crate::no_inline::attach_no_inline_directives_to_fragments; use crate::no_inline::validate_required_no_inline_directive; -use crate::util::get_normalization_operation_name; +use crate::util::get_normalization_fragment_filename; use crate::FragmentAliasMetadata; use crate::INLINE_DIRECTIVE_NAME; @@ -602,11 +602,10 @@ impl<'program, 'flag> MatchTransform<'program, 'flag> { module_directive.name.location, )]; - let mut normalization_name = get_normalization_operation_name(spread.fragment.item.0); - normalization_name.push_str(".graphql"); + let normalization_name = get_normalization_fragment_filename(spread.fragment.item); let mut operation_field_arguments = vec![build_string_literal_argument( MATCH_CONSTANTS.js_field_module_arg, - normalization_name.intern(), + normalization_name, module_directive.name.location, )]; @@ -865,7 +864,7 @@ impl<'program, 'flag> MatchTransform<'program, 'flag> { } } -impl Transformer for MatchTransform<'_, '_> { +impl Transformer<'_> for MatchTransform<'_, '_> { const NAME: &'static str = "MatchTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -1104,12 +1103,23 @@ fn validate_parent_type_of_fragment_with_read_time_resolver( transform.relay_resolver_model_unions.insert(id); } Type::Object(id) => { - return Err(Diagnostic::error( - ValidationMessage::InvalidModuleOnConcreteParentType { - object_name: transform.program.schema.object(id).name.item, - }, - spread.fragment.location, - )); + let object_has_read_time_resolver = transform + .program + .schema + .object(id) + .directives + .named(*RELAY_RESOLVER_MODEL_DIRECTIVE_NAME) + .is_some(); + + if !object_has_read_time_resolver { + return Err(Diagnostic::error( + ValidationMessage::MissingRelayResolverModelForObject { + spread_name: spread.fragment.item, + object: transform.program.schema.object(id).name.item, + }, + spread.fragment.location, + )); + } } Type::Enum(_) | Type::Scalar(_) | Type::InputObject(_) => { panic!( diff --git a/compiler/crates/relay-transforms/src/match_/split_module_import.rs b/compiler/crates/relay-transforms/src/match_/split_module_import.rs index 2ef03fcbde0ca..a915036f126c3 100644 --- a/compiler/crates/relay-transforms/src/match_/split_module_import.rs +++ b/compiler/crates/relay-transforms/src/match_/split_module_import.rs @@ -70,7 +70,7 @@ impl<'program, 'base_fragment_names> SplitModuleImportTransform<'program, 'base_ } } -impl Transformer for SplitModuleImportTransform<'_, '_> { +impl Transformer<'_> for SplitModuleImportTransform<'_, '_> { const NAME: &'static str = "SplitModuleImportTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -104,10 +104,6 @@ impl Transformer for SplitModuleImportTransform<'_, '_> { if self .base_fragment_names .contains(&module_metadata.fragment_name) - // We do not need to generate normalization files for fragments that are - // resolved entirely by read time resolver models on the client side when - // client 3D support for read time resolvers is enabled. - || module_metadata.read_time_resolvers { return self.default_transform_inline_fragment(fragment); } diff --git a/compiler/crates/relay-transforms/src/match_/subscription_transform.rs b/compiler/crates/relay-transforms/src/match_/subscription_transform.rs index fd2aeac02b47b..d8c50e5f985f5 100644 --- a/compiler/crates/relay-transforms/src/match_/subscription_transform.rs +++ b/compiler/crates/relay-transforms/src/match_/subscription_transform.rs @@ -242,7 +242,7 @@ struct ValidFieldResult<'operation> { fragment_spread: &'operation FragmentSpread, } -impl Transformer for SubscriptionTransform<'_> { +impl Transformer<'_> for SubscriptionTransform<'_> { const NAME: &'static str = "SubscriptionTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/match_/validation_message.rs b/compiler/crates/relay-transforms/src/match_/validation_message.rs index 7b103fe08b6c1..594c8d106d2e7 100644 --- a/compiler/crates/relay-transforms/src/match_/validation_message.rs +++ b/compiler/crates/relay-transforms/src/match_/validation_message.rs @@ -137,7 +137,10 @@ pub enum ValidationMessage { }, #[error( - "@module was used on a fragment with a concrete parent type: '{object_name}'. The parent type should be an interface or union." + "Invalid fragment spread '...{spread_name}'. Object '{object}' should be backed by a relay resolver model." )] - InvalidModuleOnConcreteParentType { object_name: ObjectName }, + MissingRelayResolverModelForObject { + spread_name: FragmentDefinitionName, + object: ObjectName, + }, } diff --git a/compiler/crates/relay-transforms/src/no_inline.rs b/compiler/crates/relay-transforms/src/no_inline.rs index c52d3fcda6066..a09f4d6787b1f 100644 --- a/compiler/crates/relay-transforms/src/no_inline.rs +++ b/compiler/crates/relay-transforms/src/no_inline.rs @@ -138,7 +138,7 @@ impl<'f, 'p> RequiredNoInlineValidator<'f, 'p> { } } -impl<'f, 'p> Validator for RequiredNoInlineValidator<'f, 'p> { +impl Validator for RequiredNoInlineValidator<'_, '_> { const NAME: &'static str = "RequiredNoInlineValidator"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/provided_variable_fragment_transform.rs b/compiler/crates/relay-transforms/src/provided_variable_fragment_transform.rs index 3ca3b351ffacf..55792127ddca2 100644 --- a/compiler/crates/relay-transforms/src/provided_variable_fragment_transform.rs +++ b/compiler/crates/relay-transforms/src/provided_variable_fragment_transform.rs @@ -190,7 +190,7 @@ impl<'schema> ProvidedVariableFragmentTransform<'schema> { } } -impl<'schema> Transformer for ProvidedVariableFragmentTransform<'schema> { +impl Transformer<'_> for ProvidedVariableFragmentTransform<'_> { const NAME: &'static str = "ProvidedVariableFragmentTransform"; const VISIT_ARGUMENTS: bool = true; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/refetchable_fragment.rs b/compiler/crates/relay-transforms/src/refetchable_fragment.rs index e4fa37c74e3a6..0eb3b0ec59a2c 100644 --- a/compiler/crates/relay-transforms/src/refetchable_fragment.rs +++ b/compiler/crates/relay-transforms/src/refetchable_fragment.rs @@ -41,6 +41,7 @@ use relay_config::ProjectConfig; use relay_config::SchemaConfig; use schema::SDLSchema; use schema::Schema; +pub use utils::build_used_global_variables; pub use utils::RefetchableDerivedFromMetadata; pub use utils::RefetchableMetadata; pub use utils::CONSTANTS; diff --git a/compiler/crates/relay-transforms/src/refetchable_fragment/fetchable_query_generator.rs b/compiler/crates/relay-transforms/src/refetchable_fragment/fetchable_query_generator.rs index 04b9af3eae1bf..8992a18f0bf64 100644 --- a/compiler/crates/relay-transforms/src/refetchable_fragment/fetchable_query_generator.rs +++ b/compiler/crates/relay-transforms/src/refetchable_fragment/fetchable_query_generator.rs @@ -61,6 +61,11 @@ fn build_refetch_operation( let (fetch_field_id, id_arg) = get_fetch_field_id_and_id_arg(fragment, schema, query_type, fetch_field_name)?; + let fetch_token_field = match schema_config.enable_token_field { + true => Some(schema.fetch_token_field()), + false => None, + }; + let fragment = Arc::new(FragmentDefinition { name: fragment.name, variable_definitions: fragment.variable_definitions.clone(), @@ -87,7 +92,7 @@ fn build_refetch_operation( selections: enforce_selections_with_id_field( fragment, identifier_field_id, - schema.fetch_token_field(), + fetch_token_field, ), }); let mut variable_definitions = build_operation_variable_definitions(&fragment); @@ -227,7 +232,7 @@ fn has_field(selections: &[Selection], field_id: FieldID) -> bool { fn enforce_selections_with_id_field( fragment: &FragmentDefinition, identifier_field_id: FieldID, - fetch_token_field_id: FieldID, + fetch_token_field_id: Option, ) -> Vec { let mut next_selections = fragment.selections.clone(); if !has_field(&next_selections, identifier_field_id) { @@ -238,14 +243,16 @@ fn enforce_selections_with_id_field( directives: vec![], }))); } - if !has_field(&next_selections, fetch_token_field_id) { - next_selections.push(Selection::ScalarField(Arc::new(ScalarField { - alias: None, - definition: WithLocation::generated(fetch_token_field_id), - arguments: vec![], - directives: vec![], - }))); - } + if let Some(fetch_token_field_id) = fetch_token_field_id { + if !has_field(&next_selections, fetch_token_field_id) { + next_selections.push(Selection::ScalarField(Arc::new(ScalarField { + alias: None, + definition: WithLocation::new(fragment.name.location, fetch_token_field_id), + arguments: vec![], + directives: vec![], + }))); + } + }; next_selections } diff --git a/compiler/crates/relay-transforms/src/refetchable_fragment/utils.rs b/compiler/crates/relay-transforms/src/refetchable_fragment/utils.rs index 5c141fec573bc..f2464fb55baba 100644 --- a/compiler/crates/relay-transforms/src/refetchable_fragment/utils.rs +++ b/compiler/crates/relay-transforms/src/refetchable_fragment/utils.rs @@ -18,7 +18,6 @@ use graphql_ir::Argument; use graphql_ir::Directive; use graphql_ir::FragmentDefinition; use graphql_ir::FragmentDefinitionName; -use graphql_ir::FragmentSignature; use graphql_ir::FragmentSpread; use graphql_ir::OperationDefinitionName; use graphql_ir::ProvidedVariableMetadata; @@ -88,12 +87,7 @@ pub fn build_fragment_spread(fragment: &FragmentDefinition) -> Selection { ), }) .collect(), - signature: Some(FragmentSignature { - name: fragment.name, - variable_definitions: fragment.variable_definitions.clone(), - type_condition: fragment.type_condition, - directives: fragment.directives.clone(), - }), + signature: Some(fragment.into()), })) } diff --git a/compiler/crates/relay-transforms/src/relay_actor_change.rs b/compiler/crates/relay-transforms/src/relay_actor_change.rs index 708adf8f3a50e..69daf8117cec3 100644 --- a/compiler/crates/relay-transforms/src/relay_actor_change.rs +++ b/compiler/crates/relay-transforms/src/relay_actor_change.rs @@ -70,7 +70,7 @@ impl<'program, 'feature> ActorChangeTransform<'program, 'feature> { } } -impl<'program, 'feature> Transformer for ActorChangeTransform<'program, 'feature> { +impl Transformer<'_> for ActorChangeTransform<'_, '_> { const NAME: &'static str = "ActorChangeTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/relay_resolvers.rs b/compiler/crates/relay-transforms/src/relay_resolvers.rs index b87844d8ebde7..70eedfa65868f 100644 --- a/compiler/crates/relay-transforms/src/relay_resolvers.rs +++ b/compiler/crates/relay-transforms/src/relay_resolvers.rs @@ -22,13 +22,13 @@ use docblock_shared::INJECT_FRAGMENT_DATA_ARGUMENT_NAME; use docblock_shared::LIVE_ARGUMENT_NAME; use docblock_shared::RELAY_RESOLVER_DIRECTIVE_NAME; use docblock_shared::RELAY_RESOLVER_WEAK_OBJECT_DIRECTIVE; +use docblock_shared::RESOLVER_PROPERTY_LOOKUP_NAME; use docblock_shared::TYPE_CONFIRMED_ARGUMENT_NAME; use graphql_ir::associated_data_impl; use graphql_ir::Argument; use graphql_ir::Directive; use graphql_ir::Field as IrField; use graphql_ir::FragmentDefinitionName; -use graphql_ir::FragmentSignature; use graphql_ir::FragmentSpread; use graphql_ir::InlineFragment; use graphql_ir::LinkedField; @@ -109,6 +109,12 @@ pub enum FragmentDataInjectionMode { Field { name: StringKey, is_required: bool }, // TODO: Add Support for FullData } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum ResolverSchemaGenType { + ResolverModule, + PropertyLookup { property_name: StringKey }, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct RelayResolverFieldMetadata { field_parent_type: StringKey, @@ -120,6 +126,7 @@ pub struct RelayResolverFieldMetadata { live: bool, output_type_info: ResolverOutputTypeInfo, type_confirmed: bool, + resolver_type: ResolverSchemaGenType, } associated_data_impl!(RelayResolverFieldMetadata); @@ -140,6 +147,7 @@ pub struct RelayResolverMetadata { FragmentDataInjectionMode, )>, pub type_confirmed: bool, + pub resolver_type: ResolverSchemaGenType, } associated_data_impl!(RelayResolverMetadata); @@ -253,6 +261,7 @@ impl<'program> RelayResolverSpreadTransform<'program> { ) }), type_confirmed: field_metadata.type_confirmed, + resolver_type: field_metadata.resolver_type, }; let mut new_directives: Vec = vec![resolver_metadata.into()]; @@ -266,12 +275,7 @@ impl<'program> RelayResolverSpreadTransform<'program> { Selection::FragmentSpread(Arc::new(FragmentSpread { fragment: fragment_definition.name, arguments: fragment_arguments, - signature: Some(FragmentSignature { - name: fragment_definition.name, - variable_definitions: fragment_definition.variable_definitions.clone(), - type_condition: fragment_definition.type_condition, - directives: fragment_definition.directives.clone(), - }), + signature: Some(fragment_definition.as_ref().into()), directives: new_directives, })) } else { @@ -286,7 +290,7 @@ impl<'program> RelayResolverSpreadTransform<'program> { } } -impl<'program> Transformer for RelayResolverSpreadTransform<'program> { +impl Transformer<'_> for RelayResolverSpreadTransform<'_> { const NAME: &'static str = "RelayResolversSpreadTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -312,7 +316,7 @@ impl<'program> Transformer for RelayResolverSpreadTransform<'program> { match ClientEdgeMetadata::find(fragment) { Some(client_edge_metadata) => { let backing_id_field = self - .transform_selection(&client_edge_metadata.backing_field) + .transform_selection(client_edge_metadata.backing_field) .unwrap_or_else(|| client_edge_metadata.backing_field.clone()); let selections_field = self @@ -395,7 +399,8 @@ impl<'program> RelayResolverFieldTransform<'program> { live, has_output_type, fragment_data_injection_mode, - type_confirmed + type_confirmed, + resolver_type, }) => { let mut non_required_directives = field.directives().iter().filter(|directive| { @@ -404,6 +409,7 @@ impl<'program> RelayResolverFieldTransform<'program> { && directive.name.item != *REQUIRED_DIRECTIVE_NAME && directive.name.item != *CHILDREN_CAN_BUBBLE_METADATA_KEY && directive.name.item != *CLIENT_EDGE_WATERFALL_DIRECTIVE_NAME + && directive.name.item != crate::match_::MATCH_CONSTANTS.match_directive_name }); if let Some(directive) = non_required_directives.next() { self.errors.push(Diagnostic::error( @@ -493,7 +499,8 @@ impl<'program> RelayResolverFieldTransform<'program> { live, output_type_info, fragment_data_injection_mode, - type_confirmed + type_confirmed, + resolver_type, }; let mut directives: Vec = field.directives().to_vec(); @@ -512,7 +519,7 @@ impl<'program> RelayResolverFieldTransform<'program> { } } -impl Transformer for RelayResolverFieldTransform<'_> { +impl Transformer<'_> for RelayResolverFieldTransform<'_> { const NAME: &'static str = "RelayResolversFieldTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -569,7 +576,7 @@ impl Transformer for RelayResolverFieldTransform<'_> { let transformed = match ClientEdgeMetadata::find(fragment) { Some(client_edge_metadata) => { let backing_id_field = self - .transform_selection(&client_edge_metadata.backing_field) + .transform_selection(client_edge_metadata.backing_field) .unwrap_or_else(|| client_edge_metadata.backing_field.clone()); let field_name = client_edge_metadata @@ -611,6 +618,7 @@ pub struct ResolverInfo { pub live: bool, has_output_type: bool, type_confirmed: bool, + resolver_type: ResolverSchemaGenType, } pub fn get_resolver_info( @@ -645,6 +653,13 @@ pub fn get_resolver_info( .ok(); let type_confirmed = get_bool_argument_is_true(arguments, *TYPE_CONFIRMED_ARGUMENT_NAME); + let resolver_type = + match get_argument_value(arguments, *RESOLVER_PROPERTY_LOOKUP_NAME, error_location) + .ok() + { + Some(property_name) => ResolverSchemaGenType::PropertyLookup { property_name }, + None => ResolverSchemaGenType::ResolverModule, + }; Ok(ResolverInfo { fragment_name, @@ -675,6 +690,7 @@ pub fn get_resolver_info( } }), type_confirmed, + resolver_type, }) }) } diff --git a/compiler/crates/relay-transforms/src/relay_resolvers_abstract_types.rs b/compiler/crates/relay-transforms/src/relay_resolvers_abstract_types.rs index f2d89db6f034b..e8d6620434f6b 100644 --- a/compiler/crates/relay-transforms/src/relay_resolvers_abstract_types.rs +++ b/compiler/crates/relay-transforms/src/relay_resolvers_abstract_types.rs @@ -349,7 +349,7 @@ impl RelayResolverAbstractTypesTransform<'_> { } } -impl Transformer for RelayResolverAbstractTypesTransform<'_> { +impl Transformer<'_> for RelayResolverAbstractTypesTransform<'_> { const NAME: &'static str = "RelayResolverAbstractTypesTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/remove_base_fragments.rs b/compiler/crates/relay-transforms/src/remove_base_fragments.rs index 8361fcad729e9..1f260817b6519 100644 --- a/compiler/crates/relay-transforms/src/remove_base_fragments.rs +++ b/compiler/crates/relay-transforms/src/remove_base_fragments.rs @@ -47,7 +47,7 @@ struct StripBaseFragmentsTransform<'a> { base_fragment_names: &'a FragmentDefinitionNameSet, } -impl<'a> Transformer for StripBaseFragmentsTransform<'a> { +impl Transformer<'_> for StripBaseFragmentsTransform<'_> { const NAME: &'static str = "StripBaseFragmentsTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/required_directive.rs b/compiler/crates/relay-transforms/src/required_directive.rs index 0c3b49ae2be43..740cfe0340907 100644 --- a/compiler/crates/relay-transforms/src/required_directive.rs +++ b/compiler/crates/relay-transforms/src/required_directive.rs @@ -319,7 +319,7 @@ impl<'program> RequiredDirective<'program> { } } -impl<'s> Transformer for RequiredDirective<'s> { +impl Transformer<'_> for RequiredDirective<'_> { const NAME: &'static str = "RequiredDirectiveTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -592,21 +592,25 @@ struct RequiredDirectiveVisitor<'s> { visited_fragments: FragmentDefinitionNameMap, } -impl<'s> DirectiveFinder for RequiredDirectiveVisitor<'s> { +impl DirectiveFinder for RequiredDirectiveVisitor<'_> { fn visit_directive(&self, directive: &Directive) -> bool { directive.name.item == *REQUIRED_DIRECTIVE_NAME } fn visit_fragment_spread(&mut self, fragment_spread: &graphql_ir::FragmentSpread) -> bool { - let fragment = self - .program - .fragment(fragment_spread.fragment.item) - .unwrap(); - self.visit_fragment(fragment) + let fragment = self.program.fragment(fragment_spread.fragment.item); + if let Some(frag) = fragment { + self.visit_fragment(frag) + } else { + // Could not find fragment spread. This can happen if we are running + // this transform via LSP validation where we only validate a single + // tagged template literal in isolation. + false + } } } -impl<'s> RequiredDirectiveVisitor<'s> { +impl RequiredDirectiveVisitor<'_> { fn visit_fragment(&mut self, fragment: &FragmentDefinition) -> bool { if let Some(val) = self.visited_fragments.get(&fragment.name.item) { return *val; diff --git a/compiler/crates/relay-transforms/src/rescript_relay_generate_typename.rs b/compiler/crates/relay-transforms/src/rescript_relay_generate_typename.rs index 1df8994d6cf4f..b5983827e4d5d 100644 --- a/compiler/crates/relay-transforms/src/rescript_relay_generate_typename.rs +++ b/compiler/crates/relay-transforms/src/rescript_relay_generate_typename.rs @@ -58,7 +58,7 @@ impl<'s> RescriptRelayGenerateTypenameTransform<'s> { } } -impl<'s> Transformer for RescriptRelayGenerateTypenameTransform<'s> { +impl Transformer<'_> for RescriptRelayGenerateTypenameTransform<'_> { const NAME: &'static str = "RescriptRelayGenerateTypenameTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/rescript_relay_inline_codesplit.rs b/compiler/crates/relay-transforms/src/rescript_relay_inline_codesplit.rs index bb994dc5db679..a25875c892c31 100644 --- a/compiler/crates/relay-transforms/src/rescript_relay_inline_codesplit.rs +++ b/compiler/crates/relay-transforms/src/rescript_relay_inline_codesplit.rs @@ -64,7 +64,7 @@ impl<'s> RescriptRelayInlineCodesplitTransform<'s> { } } -impl<'s> Transformer for RescriptRelayInlineCodesplitTransform<'s> { +impl Transformer<'_> for RescriptRelayInlineCodesplitTransform<'_> { const NAME: &'static str = "RescriptRelayInlineAutoCodesplitTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/rescript_relay_transform_codesplit.rs b/compiler/crates/relay-transforms/src/rescript_relay_transform_codesplit.rs index 1ca2c4a5a03b9..ca4765119b127 100644 --- a/compiler/crates/relay-transforms/src/rescript_relay_transform_codesplit.rs +++ b/compiler/crates/relay-transforms/src/rescript_relay_transform_codesplit.rs @@ -46,7 +46,7 @@ impl<'s> RescriptRelayTransformCodesplitTransform<'s> { // All inline fragments will be flattened into the top-most one in an internal Relay transform that runs after this // (flatten.rs). So, we need to make sure all relevant directives are copied onto the inline fragment that'll remain, // or else they're gone in the inline transform and we can't figure out what to code split. -impl<'s> Transformer for RescriptRelayTransformCodesplitTransform<'s> { +impl Transformer<'_> for RescriptRelayTransformCodesplitTransform<'_> { const NAME: &'static str = "RescriptRelayTransformAutoCodesplitTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/root_variables.rs b/compiler/crates/relay-transforms/src/root_variables.rs index 9882b76ca4239..7f24b4ab1f276 100644 --- a/compiler/crates/relay-transforms/src/root_variables.rs +++ b/compiler/crates/relay-transforms/src/root_variables.rs @@ -29,13 +29,19 @@ use super::RelayResolverMetadata; use crate::no_inline::NO_INLINE_DIRECTIVE_NAME; pub type VariableMap = HashMap; -type Visited = FragmentDefinitionNameMap; +pub enum VariableMapEntry { + // The variables for this entry are still being populated as a result of a + // cyclic fragment dependency. + Pending, + Populated(VariableMap), +} +pub type Visited = FragmentDefinitionNameMap; pub struct InferVariablesVisitor<'program> { /// Cache fragments as they are transformed to avoid duplicate processing. /// Because @argument values don't matter (only variable names/types), /// each reachable fragment only has to be checked once. - visited_fragments: Visited, + pub visited_fragments: Visited, program: &'program Program, } @@ -87,6 +93,7 @@ struct VariablesVisitor<'a, 'b> { program: &'a Program, local_variables: HashSet, transitive_local_variables: &'b HashSet, + cycle_detected: bool, errors: Vec, } @@ -103,6 +110,7 @@ impl<'a, 'b> VariablesVisitor<'a, 'b> { program, local_variables, transitive_local_variables, + cycle_detected: false, errors: Default::default(), } } @@ -116,15 +124,27 @@ impl VariablesVisitor<'_, '_> { /// to reanalyze variable usage. fn infer_fragment_variables(&mut self, fragment: &FragmentDefinition) -> VariableMap { if let Some(map) = self.visited_fragments.get(&fragment.name.item) { - map.clone() + match map { + VariableMapEntry::Pending => { + // We have encountered a cycle! For the purposes of the + // parent traversal, we can safely return an empty map since + // the Pending fragment is already being processed and its + // variables will get added. + // + // However, this traversal is invalid, since it does not + // include the dependencies of the Pending fragment. We + // record this here, and consumers of this visitor can + // check if a cycle was encountered and avoid caching + // results which encountered cycles. + self.cycle_detected = true; + Default::default() + } + VariableMapEntry::Populated(map) => map.clone(), + } } else { - // Break cycles by initially caching a version that is empty. - // If the current fragment is reached again, it won't have any - // root variables to add to its parents. The traversal below will - // find any root variables and update the cached version of the - // fragment. + // Populate the cache with a pending entry so we can detect if we encounter a cycle. self.visited_fragments - .insert(fragment.name.item, Default::default()); + .insert(fragment.name.item, VariableMapEntry::Pending); // Avoid collecting local variables usages as root variables let local_variables = fragment @@ -151,8 +171,20 @@ impl VariablesVisitor<'_, '_> { ); visitor.visit_fragment(fragment); let result = visitor.variable_map; - self.visited_fragments - .insert(fragment.name.item, result.clone()); + + if visitor.cycle_detected { + // If a cycle was detected, the result may be missing some + // variables, so we won't cache it. Instead, we'll clean up our + // Pending flag and force other callers to do their own traversal. + self.visited_fragments.remove(&fragment.name.item); + } else { + // If no cycle was detected, this result can safely be reused by + // other traversals, so we'll cache it for later use. + self.visited_fragments.insert( + fragment.name.item, + VariableMapEntry::Populated(result.clone()), + ); + } result } } @@ -208,7 +240,7 @@ impl VariablesVisitor<'_, '_> { } } -impl<'a, 'b> Visitor for VariablesVisitor<'a, 'b> { +impl Visitor for VariablesVisitor<'_, '_> { const NAME: &'static str = "VariablesVisitor"; const VISIT_ARGUMENTS: bool = true; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/skip_client_directives.rs b/compiler/crates/relay-transforms/src/skip_client_directives.rs index 426c721d4701a..bb5eb8d901ee1 100644 --- a/compiler/crates/relay-transforms/src/skip_client_directives.rs +++ b/compiler/crates/relay-transforms/src/skip_client_directives.rs @@ -28,7 +28,7 @@ impl<'s> SkipClientDirectives<'s> { } } -impl<'s> Transformer for SkipClientDirectives<'s> { +impl Transformer<'_> for SkipClientDirectives<'_> { const NAME: &'static str = "SkipClientDirectives"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/skip_client_extensions.rs b/compiler/crates/relay-transforms/src/skip_client_extensions.rs index fa36a2c5ca59b..96bf216d74986 100644 --- a/compiler/crates/relay-transforms/src/skip_client_extensions.rs +++ b/compiler/crates/relay-transforms/src/skip_client_extensions.rs @@ -40,7 +40,7 @@ impl<'s> SkipClientExtensionsTransform<'s> { } } -impl<'s> SkipClientExtensionsTransform<'s> { +impl SkipClientExtensionsTransform<'_> { fn is_client_directive(&self, name: DirectiveName) -> bool { // Return true if: // - directive is a custom internal directive used to hold @@ -52,7 +52,7 @@ impl<'s> SkipClientExtensionsTransform<'s> { } } -impl<'s> Transformer for SkipClientExtensionsTransform<'s> { +impl Transformer<'_> for SkipClientExtensionsTransform<'_> { const NAME: &'static str = "SkipClientExtensionsTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/skip_null_arguments_transform.rs b/compiler/crates/relay-transforms/src/skip_null_arguments_transform.rs index ad07af9da387c..d26dc068e79ee 100644 --- a/compiler/crates/relay-transforms/src/skip_null_arguments_transform.rs +++ b/compiler/crates/relay-transforms/src/skip_null_arguments_transform.rs @@ -24,7 +24,7 @@ pub fn skip_null_arguments_transform(program: &Program) -> Program { struct SkipNullArgumentsTransform; -impl Transformer for SkipNullArgumentsTransform { +impl Transformer<'_> for SkipNullArgumentsTransform { const NAME: &'static str = "SkipNullArgumentsTransform"; const VISIT_ARGUMENTS: bool = true; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/skip_split_operation.rs b/compiler/crates/relay-transforms/src/skip_split_operation.rs index 1e0db52280d29..0bfa592315cc9 100644 --- a/compiler/crates/relay-transforms/src/skip_split_operation.rs +++ b/compiler/crates/relay-transforms/src/skip_split_operation.rs @@ -25,7 +25,7 @@ pub fn skip_split_operation(program: &Program) -> Program { pub struct SkipSplitOperation; -impl Transformer for SkipSplitOperation { +impl Transformer<'_> for SkipSplitOperation { const NAME: &'static str = "SkipSplitOperationTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/skip_unreachable_node.rs b/compiler/crates/relay-transforms/src/skip_unreachable_node.rs index 8c776df688baf..69c1e471e2451 100644 --- a/compiler/crates/relay-transforms/src/skip_unreachable_node.rs +++ b/compiler/crates/relay-transforms/src/skip_unreachable_node.rs @@ -86,7 +86,7 @@ pub struct SkipUnreachableNodeTransform<'s> { defer_stream_interface: DeferStreamInterface, } -impl<'s> Transformer for SkipUnreachableNodeTransform<'s> { +impl Transformer<'_> for SkipUnreachableNodeTransform<'_> { const NAME: &'static str = "SkipUnreachableNodeTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/skip_updatable_queries.rs b/compiler/crates/relay-transforms/src/skip_updatable_queries.rs index d153a21110836..64355553118e0 100644 --- a/compiler/crates/relay-transforms/src/skip_updatable_queries.rs +++ b/compiler/crates/relay-transforms/src/skip_updatable_queries.rs @@ -30,7 +30,7 @@ impl<'s> SkipUpdatableQueries<'s> { } } -impl<'s> Transformer for SkipUpdatableQueries<'s> { +impl Transformer<'_> for SkipUpdatableQueries<'_> { const NAME: &'static str = "SkipUpdatableQueriesTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/sort_selections.rs b/compiler/crates/relay-transforms/src/sort_selections.rs index a1e53532499f4..238a6c4905029 100644 --- a/compiler/crates/relay-transforms/src/sort_selections.rs +++ b/compiler/crates/relay-transforms/src/sort_selections.rs @@ -43,7 +43,7 @@ impl<'s> SortSelectionsTransform<'s> { } } -impl Transformer for SortSelectionsTransform<'_> { +impl Transformer<'_> for SortSelectionsTransform<'_> { const NAME: &'static str = "SortSelectionsTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/test_operation_metadata.rs b/compiler/crates/relay-transforms/src/test_operation_metadata.rs index 4d0a2fb1691b5..5a56811c3a7bd 100644 --- a/compiler/crates/relay-transforms/src/test_operation_metadata.rs +++ b/compiler/crates/relay-transforms/src/test_operation_metadata.rs @@ -86,7 +86,7 @@ impl<'a> GenerateTestOperationMetadata<'a> { } } -impl<'a> Transformer for GenerateTestOperationMetadata<'a> { +impl Transformer<'_> for GenerateTestOperationMetadata<'_> { const NAME: &'static str = "GenerateTestOperationMetadata"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/transform_connections.rs b/compiler/crates/relay-transforms/src/transform_connections.rs index e55657c9be39e..a2b28ec804d08 100644 --- a/compiler/crates/relay-transforms/src/transform_connections.rs +++ b/compiler/crates/relay-transforms/src/transform_connections.rs @@ -26,11 +26,14 @@ use graphql_ir::InlineFragment; use graphql_ir::LinkedField; use graphql_ir::OperationDefinition; use graphql_ir::Program; +use graphql_ir::ProvidedVariableMetadata; use graphql_ir::Selection; use graphql_ir::Transformed; use graphql_ir::Transformer; use graphql_ir::Value; use graphql_ir::Value::Constant; +use graphql_ir::Variable; +use graphql_ir::VariableDefinition; use relay_config::DeferStreamInterface; use schema::Schema; @@ -46,15 +49,17 @@ use crate::connections::ConnectionMetadata; use crate::connections::ConnectionMetadataDirective; use crate::handle_fields::build_handle_field_directive_from_connection_directive; use crate::handle_fields::KEY_ARG_NAME; +use crate::refetchable_fragment::build_used_global_variables; use crate::relay_directive::PLURAL_ARG_NAME; use crate::relay_directive::RELAY_DIRECTIVE_NAME; +use crate::root_variables::InferVariablesVisitor; pub fn transform_connections( program: &Program, connection_interface: &ConnectionInterface, defer_stream_interface: &DeferStreamInterface, - // Does not do other validaiton and transforms only extract prefetchable pagination - // fragment. Needed for generating correct types in the typegen pipeline. + // Determines whether or not to skip other validation and transforms and only extract prefetchable + // pagination fragment. Needed for generating correct types in the typegen pipeline. only_extract_prefetchable_pagination_fragment: bool, ) -> Program { let mut transform = ConnectionTransform::new( @@ -78,6 +83,7 @@ struct ConnectionTransform<'s> { current_path: Option>, current_connection_metadata: Vec, current_document_name: StringKey, + fragment_variable_definitions: Vec, program: &'s Program, defer_stream_interface: &'s DeferStreamInterface, edge_fragments: Vec>, @@ -97,6 +103,7 @@ impl<'s> ConnectionTransform<'s> { current_path: None, current_document_name: connection_interface.cursor, // Set an arbitrary value to avoid Option current_connection_metadata: Vec::new(), + fragment_variable_definitions: Vec::new(), program, defer_stream_interface, edge_fragments: vec![], @@ -346,15 +353,15 @@ impl<'s> ConnectionTransform<'s> { let fields = std::mem::take(&mut edges_field_to_maybe_fragmentify.selections); let location = edges_field_to_maybe_fragmentify.alias_or_name_location(); - let edges_fragment = Arc::new(FragmentDefinition { + let mut edges_fragment_without_used_global_variables = FragmentDefinition { name: WithLocation::new( location, FragmentDefinitionName( format!("{}__edges", self.current_document_name).intern(), ), ), - variable_definitions: vec![], //TODO: Do we need variable_definitions?, - used_global_variables: vec![], //TODO: Do we need used_global_variables?, + variable_definitions: self.fragment_variable_definitions.clone(), + used_global_variables: vec![], type_condition: edge_type, directives: vec![Directive { name: WithLocation::new(location, *RELAY_DIRECTIVE_NAME), @@ -369,12 +376,42 @@ impl<'s> ConnectionTransform<'s> { location, }], selections: fields, - }); + }; + + // Determine used_global_variables for the edges fragment. + let variables_map = InferVariablesVisitor::new(self.program) + .infer_fragment_variables( + &edges_fragment_without_used_global_variables, + ); + edges_fragment_without_used_global_variables.used_global_variables = + build_used_global_variables( + &variables_map, + &edges_fragment_without_used_global_variables.variable_definitions, + ) + .unwrap_or_default(); + + let edges_fragment = Arc::new(edges_fragment_without_used_global_variables); edges_field_to_maybe_fragmentify.selections.push( Selection::FragmentSpread(Arc::new(FragmentSpread { fragment: edges_fragment.name, - arguments: vec![], + arguments: edges_fragment + .variable_definitions + .iter() + .filter(|def| { + ProvidedVariableMetadata::find(&def.directives).is_none() + }) + .map(|var| Argument { + name: var.name.map(|x| ArgumentName(x.0)), + value: WithLocation::new( + var.name.location, + Value::Variable(Variable { + name: var.name, + type_: var.type_.clone(), + }), + ), + }) + .collect(), signature: None, directives: vec![], })), @@ -476,7 +513,7 @@ impl<'s> ConnectionTransform<'s> { } } -impl<'s> Transformer for ConnectionTransform<'s> { +impl Transformer<'_> for ConnectionTransform<'_> { const NAME: &'static str = "ConnectionTransform"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -516,6 +553,7 @@ impl<'s> Transformer for ConnectionTransform<'s> { self.current_document_name = fragment.name.item.0; self.current_path = Some(Vec::new()); self.current_connection_metadata = Vec::new(); + self.fragment_variable_definitions = fragment.variable_definitions.clone(); let transformed = self.default_transform_fragment(fragment); if self.current_connection_metadata.is_empty() { diff --git a/compiler/crates/relay-transforms/src/unwrap_custom_directive_selection.rs b/compiler/crates/relay-transforms/src/unwrap_custom_directive_selection.rs index db4a18d100d0f..cc636f0b8dcb9 100644 --- a/compiler/crates/relay-transforms/src/unwrap_custom_directive_selection.rs +++ b/compiler/crates/relay-transforms/src/unwrap_custom_directive_selection.rs @@ -41,7 +41,7 @@ impl UnwrapCustomDirectiveSelection { } } -impl Transformer for UnwrapCustomDirectiveSelection { +impl Transformer<'_> for UnwrapCustomDirectiveSelection { const NAME: &'static str = "UnwrapCustomDirectiveSelection"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/validate_operation_variables.rs b/compiler/crates/relay-transforms/src/validate_operation_variables.rs index fa342075aee32..76bb17be8965d 100644 --- a/compiler/crates/relay-transforms/src/validate_operation_variables.rs +++ b/compiler/crates/relay-transforms/src/validate_operation_variables.rs @@ -69,7 +69,7 @@ impl<'s> ValidateOperationVariables<'s> { /// Refines the argument definitions for operations to remove unused arguments /// due to statically pruned conditional branches (e.g. because of overriding /// a variable used in `@include()` to be false). -impl<'s> Transformer for ValidateOperationVariables<'s> { +impl Transformer<'_> for ValidateOperationVariables<'_> { const NAME: &'static str = "ValidateOperationVariables"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/validations.rs b/compiler/crates/relay-transforms/src/validations.rs index b306de9032748..cf5fb7b3ee3d7 100644 --- a/compiler/crates/relay-transforms/src/validations.rs +++ b/compiler/crates/relay-transforms/src/validations.rs @@ -13,6 +13,7 @@ mod disallow_required_on_non_null_field; mod disallow_reserved_aliases; mod disallow_typename_on_root; mod rescript_relay_disallow_invalid_names; +mod validate_client_schema_extensions_use_catch; mod validate_connections; mod validate_fragment_alias_conflict; mod validate_global_variable_names; @@ -35,10 +36,10 @@ pub use disallow_circular_no_inline_fragments::disallow_circular_no_inline_fragm pub use disallow_non_node_id_fields::disallow_non_node_id_fields; pub use disallow_readtime_features_in_mutations::disallow_readtime_features_in_mutations; pub use disallow_required_on_non_null_field::disallow_required_on_non_null_field; -pub use disallow_required_on_non_null_field::disallow_required_on_non_null_field_for_executable_definition; pub use disallow_reserved_aliases::disallow_reserved_aliases; pub use disallow_typename_on_root::disallow_typename_on_root; pub use rescript_relay_disallow_invalid_names::rescript_relay_disallow_invalid_names; +pub use validate_client_schema_extensions_use_catch::validate_client_schema_extensions_use_catch; pub use validate_connections::validate_connections; pub use validate_fragment_alias_conflict::validate_fragment_alias_conflict; pub use validate_global_variable_names::validate_global_variable_names; @@ -55,3 +56,4 @@ pub use validate_server_only_directives::validate_server_only_directives; pub use validate_static_args::validate_static_args; pub use validate_unused_fragment_variables::validate_unused_fragment_variables; pub use validate_unused_variables::validate_unused_variables; +pub use validate_unused_variables::ValidateUnusedVariables; diff --git a/compiler/crates/relay-transforms/src/validations/deprecated_fields.rs b/compiler/crates/relay-transforms/src/validations/deprecated_fields.rs index e6843b2ee02e6..1266cbc04a1dd 100644 --- a/compiler/crates/relay-transforms/src/validations/deprecated_fields.rs +++ b/compiler/crates/relay-transforms/src/validations/deprecated_fields.rs @@ -105,7 +105,7 @@ impl<'a> DeprecatedFields<'a> { // While the individual methods return a diagnostic, since using deprecated fields are not errors per-se, we reserve // returning an `Err` for cases where we are unable to correctly check. // Deprecation warnings are collected in `self.warnings`. -impl<'a> Validator for DeprecatedFields<'a> { +impl Validator for DeprecatedFields<'_> { const NAME: &'static str = "DeprecatedFields"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/validations/disallow_required_on_non_null_field.rs b/compiler/crates/relay-transforms/src/validations/disallow_required_on_non_null_field.rs index 6017c726a131b..a3ff0df829904 100644 --- a/compiler/crates/relay-transforms/src/validations/disallow_required_on_non_null_field.rs +++ b/compiler/crates/relay-transforms/src/validations/disallow_required_on_non_null_field.rs @@ -15,7 +15,6 @@ use common::DirectiveName; use common::NamedItem; use errors::try2; use graphql_ir::reexport::Intern; -use graphql_ir::ExecutableDefinition; use graphql_ir::Field; use graphql_ir::FragmentDefinition; use graphql_ir::Program; @@ -37,26 +36,15 @@ lazy_static! { DirectiveName("throwOnFieldError".intern()); } -pub fn disallow_required_on_non_null_field( - schema: &Arc, - program: &Program, -) -> DiagnosticsResult> { - let mut validator = DisallowRequiredOnNonNullField::new(schema); +pub fn disallow_required_on_non_null_field(program: &Program) -> DiagnosticsResult<()> { + let mut validator = DisallowRequiredOnNonNullField::new(&program.schema); validator.validate_program(program)?; - Ok(validator.warnings) -} -pub fn disallow_required_on_non_null_field_for_executable_definition( - schema: &Arc, - definition: &ExecutableDefinition, -) -> DiagnosticsResult> { - let mut validator = DisallowRequiredOnNonNullField::new(schema); - - match definition { - ExecutableDefinition::Fragment(fragment) => validator.validate_fragment(fragment), - ExecutableDefinition::Operation(operation) => validator.validate_operation(operation), - }?; - Ok(validator.warnings) + if validator.warnings.is_empty() { + Ok(()) + } else { + Err(validator.warnings) + } } struct DisallowRequiredOnNonNullField<'a> { diff --git a/compiler/crates/relay-transforms/src/validations/validate_client_schema_extensions_use_catch.rs b/compiler/crates/relay-transforms/src/validations/validate_client_schema_extensions_use_catch.rs new file mode 100644 index 0000000000000..1ab4e684c93c4 --- /dev/null +++ b/compiler/crates/relay-transforms/src/validations/validate_client_schema_extensions_use_catch.rs @@ -0,0 +1,168 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +use std::sync::Arc; + +use common::Diagnostic; +use common::DiagnosticsResult; +use common::DirectiveName; +use common::NamedItem; +use docblock_shared::RELAY_RESOLVER_DIRECTIVE_NAME; +use docblock_shared::RELAY_RESOLVER_MODEL_GENERATED_ID_FIELD_DIRECTIVE_NAME; +use graphql_ir::reexport::Intern; +use graphql_ir::Field; +use graphql_ir::FragmentDefinition; +use graphql_ir::Program; +use graphql_ir::Validator; +use lazy_static::lazy_static; +use schema::Field as SchemaField; +use schema::SDLSchema; +use schema::Schema; +use thiserror::Error; + +use crate::CATCH_DIRECTIVE_NAME; +lazy_static! { + static ref THROW_ON_FIELD_ERROR_DIRECTIVE: DirectiveName = + DirectiveName("throwOnFieldError".intern()); +} + +/// Within @throwOnFieldError, we treat missing data as an error. However, client schema extensions +/// have no practical way to ensure that a field has been set before it is read. This means we must +/// handle the case where a field is missing data gracefully. This validator ensures that all +/// such client schema extension fields are wrapped in a @catch directive. +/// +/// Note that within a linked client schema extension, we can't use @catch because it is not +pub fn validate_client_schema_extensions_use_catch(program: &Program) -> DiagnosticsResult<()> { + let mut validator = EnsureCatch::new(&program.schema); + validator.validate_program(program) +} + +struct EnsureCatch<'a> { + schema: &'a Arc, +} + +impl<'a> EnsureCatch<'a> { + fn new(schema: &'a Arc) -> Self { + Self { schema } + } + + fn is_non_resolver_extension(&self, field: &SchemaField) -> bool { + if !field.is_extension { + return false; + } + // Relay Resolvers are added in such a way that they are marked as extensions, but they don't + // need to be wrapped in @catch since they are guaranteed by Relay Runtime to be set. + if field + .directives + .named(*RELAY_RESOLVER_DIRECTIVE_NAME) + .is_some() + { + return false; + } + + // When defining a strong resolver, Relay will create an id field. These fields + // appear as generarated fields but the Relay runtime ensures they are always set. + if field + .directives + .named(*RELAY_RESOLVER_MODEL_GENERATED_ID_FIELD_DIRECTIVE_NAME) + .is_some() + { + return false; + } + + // Special fields like __id and __typename can be ignored since their existence + // is guaranteed by Relay. They can be identified by not having a parent type. + if field.parent_type.is_none() { + return false; + } + + // The field is a client schema extension that Relay cannot guarantee is set. + true + } +} +impl Validator for EnsureCatch<'_> { + const NAME: &'static str = "validate_client_schema_extensions_use_catch"; + const VALIDATE_ARGUMENTS: bool = false; + const VALIDATE_DIRECTIVES: bool = false; + + fn validate_scalar_field(&mut self, field: &graphql_ir::ScalarField) -> DiagnosticsResult<()> { + let field_definition = self.schema.field(field.definition.item); + if !self.is_non_resolver_extension(field_definition) { + return Ok(()); + } + match field.directives.named(*CATCH_DIRECTIVE_NAME) { + Some(_) => Ok(()), + None => Err(vec![Diagnostic::error( + ValidationMessage::ClientSchemaExtenstionWithoutCatch, + field.alias_or_name_location(), + )]), + } + } + + fn validate_linked_field(&mut self, field: &graphql_ir::LinkedField) -> DiagnosticsResult<()> { + match field.directives.named(*CATCH_DIRECTIVE_NAME) { + Some(_) => Ok(()), + None => { + let field_definition = self.schema.field(field.definition.item); + if self.is_non_resolver_extension(field_definition) { + Err(vec![Diagnostic::error( + ValidationMessage::ClientSchemaExtenstionWithoutCatch, + field.alias_or_name_location(), + )]) + } else { + self.default_validate_linked_field(field) + } + } + } + } + + fn validate_inline_fragment( + &mut self, + fragment: &graphql_ir::InlineFragment, + ) -> DiagnosticsResult<()> { + match fragment.directives.named(*CATCH_DIRECTIVE_NAME) { + Some(_) => Ok(()), + None => self.default_validate_inline_fragment(fragment), + } + } + + fn validate_fragment(&mut self, fragment: &FragmentDefinition) -> DiagnosticsResult<()> { + match fragment.directives.named(*THROW_ON_FIELD_ERROR_DIRECTIVE) { + Some(_) => self.default_validate_fragment(fragment), + None => Ok(()), + } + } + + fn validate_operation( + &mut self, + operation: &graphql_ir::OperationDefinition, + ) -> DiagnosticsResult<()> { + match operation.directives.named(*THROW_ON_FIELD_ERROR_DIRECTIVE) { + Some(_) => self.default_validate_operation(operation), + None => Ok(()), + } + } +} + +#[derive( + Clone, + Debug, + Error, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + serde::Serialize +)] +#[serde(tag = "type")] +enum ValidationMessage { + #[error( + "Expected client-defined field within `@throwOnFieldError` to be annotated with `@catch`. Accessing an unset field is treated as a field error, but Relay cannot guarantee that client field will be set before they are read. Add `@catch` to explicitly handle the case where the field is unset." + )] + ClientSchemaExtenstionWithoutCatch, +} diff --git a/compiler/crates/relay-transforms/src/validations/validate_connections.rs b/compiler/crates/relay-transforms/src/validations/validate_connections.rs index 3edc7065024c5..1ef58b9b5f4a3 100644 --- a/compiler/crates/relay-transforms/src/validations/validate_connections.rs +++ b/compiler/crates/relay-transforms/src/validations/validate_connections.rs @@ -599,7 +599,7 @@ impl<'s> ConnectionValidation<'s> { } } -impl<'s> Validator for ConnectionValidation<'s> { +impl Validator for ConnectionValidation<'_> { const NAME: &'static str = "ConnectionValidation"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/validations/validate_fragment_alias_conflict.rs b/compiler/crates/relay-transforms/src/validations/validate_fragment_alias_conflict.rs index 2d74fa7277795..fcae0ad5f5390 100644 --- a/compiler/crates/relay-transforms/src/validations/validate_fragment_alias_conflict.rs +++ b/compiler/crates/relay-transforms/src/validations/validate_fragment_alias_conflict.rs @@ -113,7 +113,7 @@ impl<'s> ValidateFragmentAliasConflict<'s> { } } -impl<'a> Validator for ValidateFragmentAliasConflict<'a> { +impl Validator for ValidateFragmentAliasConflict<'_> { const NAME: &'static str = "ValidateFragmentAliasConflict"; const VALIDATE_ARGUMENTS: bool = false; diff --git a/compiler/crates/relay-transforms/src/validations/validate_no_inline_with_raw_response_type.rs b/compiler/crates/relay-transforms/src/validations/validate_no_inline_with_raw_response_type.rs index 2c52b0a18d905..0a3aeb95cc26b 100644 --- a/compiler/crates/relay-transforms/src/validations/validate_no_inline_with_raw_response_type.rs +++ b/compiler/crates/relay-transforms/src/validations/validate_no_inline_with_raw_response_type.rs @@ -50,7 +50,7 @@ impl<'a> NoInlineRawResponseTypeValidator<'a> { } } -impl<'a> Validator for NoInlineRawResponseTypeValidator<'a> { +impl Validator for NoInlineRawResponseTypeValidator<'_> { const NAME: &'static str = "NoInlineRawResponseTypeValidator"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/validations/validate_no_unselectable_selections.rs b/compiler/crates/relay-transforms/src/validations/validate_no_unselectable_selections.rs index 77cacb0e020aa..4bd00307fa150 100644 --- a/compiler/crates/relay-transforms/src/validations/validate_no_unselectable_selections.rs +++ b/compiler/crates/relay-transforms/src/validations/validate_no_unselectable_selections.rs @@ -90,7 +90,7 @@ impl<'a, 'b> UnselectableSelections<'a, 'b> { } } -impl<'a, 'b> Validator for UnselectableSelections<'a, 'b> { +impl Validator for UnselectableSelections<'_, '_> { const NAME: &'static str = "UnselectableSelections"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = false; diff --git a/compiler/crates/relay-transforms/src/validations/validate_server_only_directives.rs b/compiler/crates/relay-transforms/src/validations/validate_server_only_directives.rs index 7e21398c7192f..8c981f5c0d66d 100644 --- a/compiler/crates/relay-transforms/src/validations/validate_server_only_directives.rs +++ b/compiler/crates/relay-transforms/src/validations/validate_server_only_directives.rs @@ -131,7 +131,7 @@ impl<'s> ServerOnlyDirectivesValidation<'s> { } } -impl<'s> Validator for ServerOnlyDirectivesValidation<'s> { +impl Validator for ServerOnlyDirectivesValidation<'_> { const NAME: &'static str = "ServerOnlyDirectivesValidation"; const VALIDATE_ARGUMENTS: bool = false; const VALIDATE_DIRECTIVES: bool = true; diff --git a/compiler/crates/relay-transforms/src/validations/validate_static_args.rs b/compiler/crates/relay-transforms/src/validations/validate_static_args.rs index 04da0c3f479ec..01b82d51b3f97 100644 --- a/compiler/crates/relay-transforms/src/validations/validate_static_args.rs +++ b/compiler/crates/relay-transforms/src/validations/validate_static_args.rs @@ -53,7 +53,7 @@ impl<'a> StaticArgValidator<'a> { } } -impl<'a> Validator for StaticArgValidator<'a> { +impl Validator for StaticArgValidator<'_> { const NAME: &'static str = "StaticArgValidator"; // Eliding default argument checks as we're overriding specific argument checks for certain types const VALIDATE_ARGUMENTS: bool = false; diff --git a/compiler/crates/relay-transforms/src/validations/validate_unused_variables.rs b/compiler/crates/relay-transforms/src/validations/validate_unused_variables.rs index 95a7edda47b79..649805984fa2e 100644 --- a/compiler/crates/relay-transforms/src/validations/validate_unused_variables.rs +++ b/compiler/crates/relay-transforms/src/validations/validate_unused_variables.rs @@ -23,12 +23,12 @@ pub fn validate_unused_variables(program: &Program) -> DiagnosticsResult<()> { } pub struct ValidateUnusedVariables<'program> { - visitor: InferVariablesVisitor<'program>, + pub visitor: InferVariablesVisitor<'program>, ignore_directive_name: DirectiveName, } impl<'program> ValidateUnusedVariables<'program> { - fn new(program: &'program Program) -> Self { + pub fn new(program: &'program Program) -> Self { Self { visitor: InferVariablesVisitor::new(program), ignore_directive_name: DirectiveName( diff --git a/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.expected b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.expected new file mode 100644 index 0000000000000..6a59c3719fb13 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.expected @@ -0,0 +1,20 @@ +==================================== INPUT ==================================== +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment @arguments(cond: false) + } +} + +fragment Fragment on User + @argumentDefinitions(cond: {type: "Boolean!"}) { + lastName @include(if: $cond) +} +==================================== ERROR ==================================== +✖︎ After applying transforms to the query `EmptyQuery` selections of the `EmptyQuery` that would be sent to the server are empty. This is likely due to the use of `@skip`/`@include` directives with constant values that remove all selections in the query. + + empty-selection-constant-include-false-argument.graphql:2:7 + 1 │ # expected-to-throw + 2 │ query EmptyQuery($id: ID!) { + │ ^^^^^^^^^^ + 3 │ node(id: $id) { diff --git a/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.graphql b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.graphql new file mode 100644 index 0000000000000..f4fa1bcb931d6 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.graphql @@ -0,0 +1,11 @@ +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment @arguments(cond: false) + } +} + +fragment Fragment on User + @argumentDefinitions(cond: {type: "Boolean!"}) { + lastName @include(if: $cond) +} diff --git a/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.expected b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.expected new file mode 100644 index 0000000000000..ccf1986cb5875 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.expected @@ -0,0 +1,20 @@ +==================================== INPUT ==================================== +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment @arguments(cond: true) + } +} + +fragment Fragment on User + @argumentDefinitions(cond: {type: "Boolean!"}) { + lastName @skip(if: $cond) +} +==================================== ERROR ==================================== +✖︎ After applying transforms to the query `EmptyQuery` selections of the `EmptyQuery` that would be sent to the server are empty. This is likely due to the use of `@skip`/`@include` directives with constant values that remove all selections in the query. + + empty-selection-constant-skip-true-argument.graphql:2:7 + 1 │ # expected-to-throw + 2 │ query EmptyQuery($id: ID!) { + │ ^^^^^^^^^^ + 3 │ node(id: $id) { diff --git a/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.graphql b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.graphql new file mode 100644 index 0000000000000..a763cf6444a27 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.graphql @@ -0,0 +1,11 @@ +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment @arguments(cond: true) + } +} + +fragment Fragment on User + @argumentDefinitions(cond: {type: "Boolean!"}) { + lastName @skip(if: $cond) +} diff --git a/compiler/crates/relay-transforms/tests/apply_fragment_arguments_test.rs b/compiler/crates/relay-transforms/tests/apply_fragment_arguments_test.rs index 6cd98cd2fec03..cfa5957d0f913 100644 --- a/compiler/crates/relay-transforms/tests/apply_fragment_arguments_test.rs +++ b/compiler/crates/relay-transforms/tests/apply_fragment_arguments_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<7a0be220ee0ccec98d9d78d2768944ba>> + * @generated SignedSource<<015f5d0f887cfdca2bff8cd762cc2a55>> */ mod apply_fragment_arguments; @@ -26,6 +26,20 @@ async fn deletes_unreferenced_fragments() { test_fixture(transform_fixture, file!(), "deletes-unreferenced-fragments.graphql", "apply_fragment_arguments/fixtures/deletes-unreferenced-fragments.expected", input, expected).await; } +#[tokio::test] +async fn empty_selection_constant_include_false_argument() { + let input = include_str!("apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.graphql"); + let expected = include_str!("apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.expected"); + test_fixture(transform_fixture, file!(), "empty-selection-constant-include-false-argument.graphql", "apply_fragment_arguments/fixtures/empty-selection-constant-include-false-argument.expected", input, expected).await; +} + +#[tokio::test] +async fn empty_selection_constant_skip_true_argument() { + let input = include_str!("apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.graphql"); + let expected = include_str!("apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.expected"); + test_fixture(transform_fixture, file!(), "empty-selection-constant-skip-true-argument.graphql", "apply_fragment_arguments/fixtures/empty-selection-constant-skip-true-argument.expected", input, expected).await; +} + #[tokio::test] async fn fragment_include_with_provided_argument() { let input = include_str!("apply_fragment_arguments/fixtures/fragment-include-with-provided-argument.graphql"); diff --git a/compiler/crates/relay-transforms/tests/assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.expected b/compiler/crates/relay-transforms/tests/assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.expected new file mode 100644 index 0000000000000..e097fcbcbfa55 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.expected @@ -0,0 +1,24 @@ +==================================== INPUT ==================================== +query TestQuery { + node(id: "4") { + ...Assignable_user @dangerously_unaliased_fixme + } +} + +fragment Assignable_user on User @assignable { + __typename +} +==================================== OUTPUT =================================== +query TestQuery { + node(id: "4") { + ... { + ...Assignable_user @dangerously_unaliased_fixme + __typename + __id + } + } +} + +fragment Assignable_user on User @assignable { + __typename +} diff --git a/compiler/crates/relay-transforms/tests/assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.graphql b/compiler/crates/relay-transforms/tests/assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.graphql new file mode 100644 index 0000000000000..543b0b8ca0ae2 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.graphql @@ -0,0 +1,9 @@ +query TestQuery { + node(id: "4") { + ...Assignable_user @dangerously_unaliased_fixme + } +} + +fragment Assignable_user on User @assignable { + __typename +} diff --git a/compiler/crates/relay-transforms/tests/assignable_fragment_spread_test.rs b/compiler/crates/relay-transforms/tests/assignable_fragment_spread_test.rs index bb0b2d9e3640e..39cfb79fad324 100644 --- a/compiler/crates/relay-transforms/tests/assignable_fragment_spread_test.rs +++ b/compiler/crates/relay-transforms/tests/assignable_fragment_spread_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2e19314c2dbf23eef2878bbb537fba0e>> + * @generated SignedSource<<6eb30dc78dfe1878bc1456bffe63bb3c>> */ mod assignable_fragment_spread; @@ -54,6 +54,13 @@ async fn assignable_fragment_spread_with_directives_invalid() { test_fixture(transform_fixture, file!(), "assignable-fragment-spread-with-directives.invalid.graphql", "assignable_fragment_spread/fixtures/assignable-fragment-spread-with-directives.invalid.expected", input, expected).await; } +#[tokio::test] +async fn assignable_fragment_spread_with_fixme_directives() { + let input = include_str!("assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.graphql"); + let expected = include_str!("assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.expected"); + test_fixture(transform_fixture, file!(), "assignable-fragment-spread-with-fixme-directives.graphql", "assignable_fragment_spread/fixtures/assignable-fragment-spread-with-fixme-directives.expected", input, expected).await; +} + #[tokio::test] async fn assignable_fragment_spread_within_inline_fragment() { let input = include_str!("assignable_fragment_spread/fixtures/assignable-fragment-spread-within-inline-fragment.graphql"); diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment-no-type-condition.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment-no-type-condition.expected index 08a7779c285da..1995b25884d40 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment-no-type-condition.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment-no-type-condition.expected @@ -48,6 +48,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { @@ -76,6 +77,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment.expected index 18240bc4574d2..4e51ee3b61528 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-inline-fragment.expected @@ -53,6 +53,7 @@ fragment Foo_node on Node { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { @@ -83,6 +84,7 @@ fragment Foo_node on Node { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-interface.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-interface.expected index 17d4ebdf07413..20d6d5b649fef 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-interface.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-interface.expected @@ -61,6 +61,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } best_friend { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-object.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-object.expected index 4f434a5b68d90..65cb672e5767b 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-object.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-object.expected @@ -47,6 +47,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } best_friend { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-union.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-union.expected index d9be430f4e233..ff4e74027ad33 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-union.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-to-client-union.expected @@ -64,6 +64,7 @@ fragment FeedbackFragmentType on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } feedback_as_union { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-variables.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-variables.expected index a3a16f6f254ec..5cfd307b1c8c0 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-variables.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-variables.expected @@ -40,6 +40,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-with-required.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-with-required.expected index 596fe13d6b5b0..5958457727771 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-with-required.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-with-required.expected @@ -44,6 +44,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall @required(action: NONE) best_friend @waterfall @required(action: NONE) { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-within-non-client-edge.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-within-non-client-edge.expected index 5cfc76b0db944..50682f26bb2d6 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-within-non-client-edge.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge-within-non-client-edge.expected @@ -43,6 +43,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge.expected index 515a2f6e0db2d..303686c8cdcbb 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/client-edge.expected @@ -40,6 +40,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges-with-variables.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges-with-variables.expected index 94385c5dfe646..bd60b094534a4 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges-with-variables.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges-with-variables.expected @@ -44,6 +44,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { @@ -68,6 +69,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { @@ -128,6 +130,7 @@ fragment RefetchableClientEdgeQuery_Foo_user_best_friend on User @__ClientEdgeGe # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges.expected index d0292135b81ba..a5f453518e6c3 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-client-edges.expected @@ -42,6 +42,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { @@ -65,6 +66,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { @@ -123,6 +125,7 @@ fragment RefetchableClientEdgeQuery_Foo_user_best_friend on User @__ClientEdgeGe # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @waterfall best_friend @waterfall { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path-with-alias.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path-with-alias.expected index 6f9a80a231c22..0e4c03b0939c7 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path-with-alias.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path-with-alias.expected @@ -55,6 +55,7 @@ fragment Foo_user on ClientUser { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } bff: best_friend { @@ -83,6 +84,7 @@ fragment Foo_user on ClientUser { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } bffs_bff: best_friend { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path.expected index e0016e0fd3f1c..d9e206772dd9a 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/nested-path.expected @@ -53,6 +53,7 @@ fragment Foo_user on ClientUser { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } best_friend { @@ -79,6 +80,7 @@ fragment Foo_user on ClientUser { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } best_friend { diff --git a/compiler/crates/relay-transforms/tests/client_edges/fixtures/output-type.expected b/compiler/crates/relay-transforms/tests/client_edges/fixtures/output-type.expected index 4e0a473eadf11..97e8d0e996490 100644 --- a/compiler/crates/relay-transforms/tests/client_edges/fixtures/output-type.expected +++ b/compiler/crates/relay-transforms/tests/client_edges/fixtures/output-type.expected @@ -59,6 +59,7 @@ fragment Foo_user on User { # ), # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } best_friend { diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field.rs b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field.rs index 253140dccda5b..30aec4a222bed 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field.rs +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field.rs @@ -15,6 +15,7 @@ use graphql_syntax::parse_executable; use graphql_test_helpers::diagnostics_to_sorted_string; use relay_test_schema::get_test_schema_with_extensions; use relay_transforms::disallow_required_on_non_null_field; +use relay_transforms::required_directive; pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result { let parts: Vec<_> = fixture.content.split("%extensions%").collect(); @@ -28,14 +29,14 @@ pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result let ir = build(&schema, &ast.definitions) .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?; let program = Program::from_definitions(Arc::clone(&schema), ir); - let results = disallow_required_on_non_null_field(&Arc::clone(&schema), &program) - .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?; + let program = required_directive(&program).unwrap(); + let results = disallow_required_on_non_null_field(&program) + .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics)); - Ok(format!( - "OK; warnings: {}", - diagnostics_to_sorted_string(fixture.content, &results) - ) - .to_owned()) + match results { + Ok(_) => Ok("OK".to_owned()), + Err(diagnostics) => Ok(format!("OK; warnings: {}", diagnostics).to_owned()), + } } else { panic!("Expected exactly one %extensions% section marker.") } diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/fragment_with_required_semantic_field_no_explicit_errors.expected b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/fragment_with_required_semantic_field_no_explicit_errors.expected index 863c8ed45bc68..5938d97f31d44 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/fragment_with_required_semantic_field_no_explicit_errors.expected +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/fragment_with_required_semantic_field_no_explicit_errors.expected @@ -8,4 +8,4 @@ extend type User { some_field: Int @semanticNonNull } ==================================== OUTPUT =================================== -OK; warnings: +OK diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field.expected b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field.expected index 4d54f0cb17573..ee0202ffd8710 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field.expected +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field.expected @@ -8,4 +8,4 @@ extend type Query { some_field: Int } ==================================== OUTPUT =================================== -OK; warnings: +OK diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field_no_explicit_errors.expected b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field_no_explicit_errors.expected index ec111e95ff3ea..1f64e6b35c5eb 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field_no_explicit_errors.expected +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_field_no_explicit_errors.expected @@ -8,4 +8,4 @@ extend type Query { some_field: Int } ==================================== OUTPUT =================================== -OK; warnings: +OK diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_semantic_field_no_explicit_errors.expected b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_semantic_field_no_explicit_errors.expected index 88950494640e4..57e09179d547d 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_semantic_field_no_explicit_errors.expected +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_required_semantic_field_no_explicit_errors.expected @@ -8,4 +8,4 @@ extend type Query { some_field: Int @semanticNonNull } ==================================== OUTPUT =================================== -OK; warnings: +OK diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field.expected b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field.expected index 57c0067cd24d7..0e9b12a81d7e1 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field.expected +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field.expected @@ -8,4 +8,4 @@ extend type Query { some_field: Int @semanticNonNull } ==================================== OUTPUT =================================== -OK; warnings: +OK diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field_no_explicit_errors.expected b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field_no_explicit_errors.expected index 817215a17eaa2..d7e2654ae14d2 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field_no_explicit_errors.expected +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/query_with_semantic_field_no_explicit_errors.expected @@ -8,4 +8,4 @@ extend type Query { some_field: Int @semanticNonNull } ==================================== OUTPUT =================================== -OK; warnings: +OK diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.expected b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.expected new file mode 100644 index 0000000000000..bfd2baccfde00 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.expected @@ -0,0 +1,17 @@ +==================================== INPUT ==================================== +query MyQuery @throwOnFieldError { + my_field @required(action: LOG) { + some_field @required(action: LOG) + } +} + +# %extensions% +extend type Query { + my_field: MyType @semanticNonNull +} + +type MyType { + some_field: Int +} +==================================== OUTPUT =================================== +OK diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.graphql b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.graphql new file mode 100644 index 0000000000000..458a60db0a44e --- /dev/null +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.graphql @@ -0,0 +1,14 @@ +query MyQuery @throwOnFieldError { + my_field @required(action: LOG) { + some_field @required(action: LOG) + } +} + +# %extensions% +extend type Query { + my_field: MyType @semanticNonNull +} + +type MyType { + some_field: Int +} diff --git a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field_test.rs b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field_test.rs index eecfd83851b00..abf21357b29eb 100644 --- a/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field_test.rs +++ b/compiler/crates/relay-transforms/tests/disallow_required_on_non_null_field_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1aeb23bd73757d57be6f0348658290e5>> + * @generated SignedSource<<12d7bd117492254376fcbcd30baf95f6>> */ mod disallow_required_on_non_null_field; @@ -109,3 +109,10 @@ async fn query_with_semantic_field_no_explicit_errors() { let expected = include_str!("disallow_required_on_non_null_field/fixtures/query_with_semantic_field_no_explicit_errors.expected"); test_fixture(transform_fixture, file!(), "query_with_semantic_field_no_explicit_errors.graphql", "disallow_required_on_non_null_field/fixtures/query_with_semantic_field_no_explicit_errors.expected", input, expected).await; } + +#[tokio::test] +async fn required_bubbles_to_required_semantic_field() { + let input = include_str!("disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.graphql"); + let expected = include_str!("disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.expected"); + test_fixture(transform_fixture, file!(), "required_bubbles_to_required_semantic_field.graphql", "disallow_required_on_non_null_field/fixtures/required_bubbles_to_required_semantic_field.expected", input, expected).await; +} diff --git a/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.expected b/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.expected index 7fc318b9fb52f..6fc095ce8a9bb 100644 --- a/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.expected +++ b/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.expected @@ -1,5 +1,4 @@ ==================================== INPUT ==================================== -# expected-to-throw fragment NameRendererFragment on Persona { id basicUser { @@ -24,11 +23,37 @@ type BasicUser @__RelayResolverModel { address: String __relay_model_instance: RelayResolverValue @relay_resolver(import_path: "ClientUserResolver", fragment_name: "ClientUser__id", inject_fragment_data: "id") } -==================================== ERROR ==================================== -✖︎ @module was used on a fragment with a concrete parent type: 'BasicUser'. The parent type should be an interface or union. +==================================== OUTPUT =================================== +fragment ClientUser_Fragment on BasicUser { + name + address +} - client-3D-module-on-concrete-parent-type.invalid.graphql:5:8 - 4 │ basicUser { - 5 │ ...ClientUser_Fragment @module(name: "ClientUser.react") - │ ^^^^^^^^^^^^^^^^^^^ - 6 │ } +fragment NameRendererFragment on Persona { + id + basicUser { + ... on BasicUser { + ... on BasicUser @__ModuleMetadata + # ModuleMetadata { + # location: client-3D-module-on-concrete-parent-type.invalid.graphql:89:96, + # key: "NameRendererFragment", + # module_id: "NameRendererFragment.basicUser", + # module_name: "ClientUser.react", + # source_document_name: FragmentDefinitionName( + # FragmentDefinitionName( + # "NameRendererFragment", + # ), + # ), + # read_time_resolvers: true, + # fragment_name: FragmentDefinitionName( + # "ClientUser_Fragment", + # ), + # fragment_source_location: client-3D-module-on-concrete-parent-type.invalid.graphql:139:158, + # no_inline: false, + # } + { + ...ClientUser_Fragment + } + } + } +} diff --git a/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.graphql b/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.graphql index 21b3267522f90..bc7037d1ece47 100644 --- a/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.graphql +++ b/compiler/crates/relay-transforms/tests/match_transform_client_resolver/fixtures/client-3D-module-on-concrete-parent-type.invalid.graphql @@ -1,4 +1,3 @@ -# expected-to-throw fragment NameRendererFragment on Persona { id basicUser { diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment.rs b/compiler/crates/relay-transforms/tests/refetchable_fragment.rs index 1bf80be1b247c..31032b98aa1d0 100644 --- a/compiler/crates/relay-transforms/tests/refetchable_fragment.rs +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment.rs @@ -8,6 +8,7 @@ use fixture_tests::Fixture; use graphql_test_helpers::apply_transform_for_test; use relay_config::DeferStreamInterface; +use relay_config::ProjectConfig; use relay_transforms::transform_connections; use relay_transforms::transform_refetchable_fragment; use relay_transforms::ConnectionInterface; @@ -21,12 +22,18 @@ pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result false, ); let base_fragments = Default::default(); - transform_refetchable_fragment( - &program, - &Default::default(), - &base_fragments, - false, - vec![], - ) + let schema_config = if fixture.content.contains("// enable-token-field: true") { + relay_config::SchemaConfig { + enable_token_field: true, + ..Default::default() + } + } else { + Default::default() + }; + let project_config = ProjectConfig { + schema_config, + ..Default::default() + }; + transform_refetchable_fragment(&program, &project_config, &base_fragments, false, vec![]) }) } diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.expected b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.expected new file mode 100644 index 0000000000000..33797b14a293b --- /dev/null +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.expected @@ -0,0 +1,60 @@ +==================================== INPUT ==================================== +# // enable-token-field: true + +fragment RefetchableFragment on NonNodeStory + @refetchable(queryName: "RefetchableFragmentQuery") { + actor { + ...ProfilePicture + } +} + +fragment ProfilePicture on User { + profilePicture(size: $size) { + uri + } +} +==================================== OUTPUT =================================== +query RefetchableFragmentQuery( + $size: [Int] + $id: ID! +) @__RefetchableDerivedFromMetadata +# RefetchableDerivedFromMetadata( +# FragmentDefinitionName( +# "RefetchableFragment", +# ), +# ) + { + fetch__NonNodeStory(input_fetch_id: $id) { + ...RefetchableFragment + } +} + +fragment ProfilePicture on User { + profilePicture(size: $size) { + uri + } +} + +fragment RefetchableFragment on NonNodeStory @refetchable(queryName: "RefetchableFragmentQuery") @__RefetchableMetadata +# RefetchableMetadata { +# operation_name: OperationDefinitionName( +# "RefetchableFragmentQuery", +# ), +# path: [ +# "fetch__NonNodeStory", +# ], +# identifier_info: Some( +# RefetchableIdentifierInfo { +# identifier_field: "fetch_id", +# identifier_query_variable_name: "id", +# }, +# ), +# is_prefetchable_pagination: false, +# } + { + actor { + ...ProfilePicture + } + fetch_id + __token +} diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.graphql b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.graphql new file mode 100644 index 0000000000000..5336685e87e88 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.graphql @@ -0,0 +1,14 @@ +# // enable-token-field: true + +fragment RefetchableFragment on NonNodeStory + @refetchable(queryName: "RefetchableFragmentQuery") { + actor { + ...ProfilePicture + } +} + +fragment ProfilePicture on User { + profilePicture(size: $size) { + uri + } +} diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type.expected b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type.expected index 078a78736c942..1056b588e0b82 100644 --- a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type.expected +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type.expected @@ -54,5 +54,4 @@ fragment RefetchableFragment on NonNodeStory @refetchable(queryName: "Refetchabl ...ProfilePicture } fetch_id - __token } diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-but-no-implementing-types.expected b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-but-no-implementing-types.expected index b8974e7f3b0ed..a2f057ebf52ba 100644 --- a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-but-no-implementing-types.expected +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-but-no-implementing-types.expected @@ -47,5 +47,4 @@ fragment RefetchableFragmentFoo on RefetchableInterfaceFoo @refetchable(queryNam # } { id - __token } diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-some-types-impl-node.expected b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-some-types-impl-node.expected index 7f401fadbb1cc..0a2af5ba85e5a 100644 --- a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-some-types-impl-node.expected +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface-some-types-impl-node.expected @@ -54,5 +54,4 @@ fragment RefetchableFragment on RefetchableInterface @refetchable(queryName: "Re # } { id - __token } diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface.expected b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface.expected index 3f1d6beab77ba..dffb237076cd4 100644 --- a/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface.expected +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment/fixtures/refetchable-interface.expected @@ -78,7 +78,6 @@ fragment RefetchableFragment on RefetchableInterface @refetchable(queryName: "Re # } { id - __token } fragment RefetchableFragment2 on RefetchableInterface2 @refetchable(queryName: "RefetchableFragmentQuery2") @__RefetchableMetadata @@ -100,5 +99,4 @@ fragment RefetchableFragment2 on RefetchableInterface2 @refetchable(queryName: " { __typename not_id - __token } diff --git a/compiler/crates/relay-transforms/tests/refetchable_fragment_test.rs b/compiler/crates/relay-transforms/tests/refetchable_fragment_test.rs index 5b2a382ed1b05..ade8bd191fe97 100644 --- a/compiler/crates/relay-transforms/tests/refetchable_fragment_test.rs +++ b/compiler/crates/relay-transforms/tests/refetchable_fragment_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<63626487811055e17831fb93aee7ca44>> + * @generated SignedSource<<733f08cd406c19e1403b12a718566e81>> */ mod refetchable_fragment; @@ -68,6 +68,13 @@ async fn fragment_on_non_node_fetchable_type() { test_fixture(transform_fixture, file!(), "fragment-on-non-node-fetchable-type.graphql", "refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type.expected", input, expected).await; } +#[tokio::test] +async fn fragment_on_non_node_fetchable_type_with_token_field() { + let input = include_str!("refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.graphql"); + let expected = include_str!("refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.expected"); + test_fixture(transform_fixture, file!(), "fragment-on-non-node-fetchable-type-with-token-field.graphql", "refetchable_fragment/fixtures/fragment-on-non-node-fetchable-type-with-token-field.expected", input, expected).await; +} + #[tokio::test] async fn fragment_on_object_implementing_node_interface() { let input = include_str!("refetchable_fragment/fixtures/fragment-on-object-implementing-node-interface.graphql"); diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/field-alias.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/field-alias.expected index da12ad2a18575..09eda975ae018 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/field-alias.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/field-alias.expected @@ -34,6 +34,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/missing-fragment-name.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/missing-fragment-name.expected index 00987d089eec7..cfb715e559441 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/missing-fragment-name.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/missing-fragment-name.expected @@ -22,6 +22,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/multiple-relay-resolvers.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/multiple-relay-resolvers.expected index b3d9a0bc35cb0..90cd32ee762db 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/multiple-relay-resolvers.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/multiple-relay-resolvers.expected @@ -38,6 +38,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } ...HobbitNameResolverFragment_name @__RelayResolverMetadata @@ -52,6 +53,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/nested-relay-resolver.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/nested-relay-resolver.expected index 211212beb1102..cc0caf7b6a990 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/nested-relay-resolver.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/nested-relay-resolver.expected @@ -38,6 +38,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } @@ -56,6 +57,7 @@ fragment HobbitNameResolverFragment_name on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-backing-client-edge.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-backing-client-edge.expected index 3a29d5cbd70e9..e05c71733b421 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-backing-client-edge.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-backing-client-edge.expected @@ -36,6 +36,7 @@ fragment Foo_user on User { # output_type_info: EdgeTo, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-field-and-fragment-arguments.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-field-and-fragment-arguments.expected index a86fb9a6b3126..22dbf98d9cbfe 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-field-and-fragment-arguments.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-field-and-fragment-arguments.expected @@ -44,6 +44,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @arguments(fragment_arg: 1) } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-model.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-model.expected index e2992b7896a9b..6a1cb3c58ea33 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-model.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-model.expected @@ -45,6 +45,7 @@ fragment Foo_user on User { # ), # ), # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-named-import.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-named-import.expected index 27f55a07d24b5..512d6b7b142fd 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-named-import.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-named-import.expected @@ -34,6 +34,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-required.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-required.expected index 772bcabe0e929..3b1442955c4cd 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-required.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-required.expected @@ -32,6 +32,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } @required(action: THROW) } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments-with-alias.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments-with-alias.expected index 5cea5e6a2feff..00d7b4a050a37 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments-with-alias.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments-with-alias.expected @@ -40,6 +40,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } __id @__RelayResolverMetadata @@ -73,6 +74,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments.expected index b9a10d31df160..0aa4960153838 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-scalar-field-arguments.expected @@ -39,6 +39,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-within-named-inline-fragment.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-within-named-inline-fragment.expected index 60e1a3c32fdae..f614823ad06ed 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-within-named-inline-fragment.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver-within-named-inline-fragment.expected @@ -45,6 +45,7 @@ fragment Foo_user on Node { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver.expected b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver.expected index 08cdd2cd6118e..2a19606b96f3b 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers/fixtures/relay-resolver.expected @@ -32,6 +32,7 @@ fragment Foo_user on User { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/condition_on_inline_fragment_without_type_on_interface.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/condition_on_inline_fragment_without_type_on_interface.expected index bed548d5caf09..01af997409796 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/condition_on_inline_fragment_without_type_on_interface.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/condition_on_inline_fragment_without_type_on_interface.expected @@ -40,6 +40,7 @@ fragment conditionOnInlineFragmentWithoutTypeOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } __id @__RelayResolverMetadata @@ -54,6 +55,7 @@ fragment conditionOnInlineFragmentWithoutTypeOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_nested_selections_on_interface.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_nested_selections_on_interface.expected index b7812f17151ae..078ec8c6e4d6b 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_nested_selections_on_interface.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_nested_selections_on_interface.expected @@ -56,6 +56,7 @@ fragment conditionsOnNestedSelectionsOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } @@ -76,6 +77,7 @@ fragment conditionsOnNestedSelectionsOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_selections_on_interface.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_selections_on_interface.expected index e702b45162fa4..1548e5de1ee5b 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_selections_on_interface.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/conditions_on_selections_on_interface.expected @@ -41,6 +41,7 @@ fragment conditionsOnSelectionsOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } @@ -60,6 +61,7 @@ fragment conditionsOnSelectionsOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type.expected index 633e163ff44c6..026f747bd126c 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type.expected @@ -40,6 +40,7 @@ query edgeToAbstractTypeQuery { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment.expected index 87b2a932c794d..3c19f7b50c156 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment.expected @@ -52,6 +52,7 @@ query edgeToAbstractTypeWithInlineFragmentQuery { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment_on_abstract_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment_on_abstract_type.expected index f855013a28b4b..f73aa0f5de4a2 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment_on_abstract_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/edge_to_abstract_type_with_inline_fragment_on_abstract_type.expected @@ -48,6 +48,7 @@ query edgeToAbstractTypeWithInlineFragmentOnAbstractTypeQuery { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/extend_server_defined_concrete_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/extend_server_defined_concrete_type.expected index 5ece2fb3f72fe..8b2d3c45b2b72 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/extend_server_defined_concrete_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/extend_server_defined_concrete_type.expected @@ -29,6 +29,7 @@ fragment extendServerDefinedConcreteTypeFragment on FeedUnit { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/fragment_on_abstract_type_enabled.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/fragment_on_abstract_type_enabled.expected index 631f0d2468df6..fad3f692e9924 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/fragment_on_abstract_type_enabled.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/fragment_on_abstract_type_enabled.expected @@ -41,6 +41,7 @@ fragment fragmentOnAbstractTypeEnabledFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/inline_fragment_without_type_condition_on_interface.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/inline_fragment_without_type_condition_on_interface.expected index 9ed95814c0234..2ad4f27e0c066 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/inline_fragment_without_type_condition_on_interface.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/inline_fragment_without_type_condition_on_interface.expected @@ -45,6 +45,7 @@ fragment inlineFragmentWithoutTypeConditionOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_fragment.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_fragment.expected index 2e7ea8c7588d7..ef3d396e9c3ef 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_fragment.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_fragment.expected @@ -44,6 +44,7 @@ fragment nestedAbstractTypeFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_query.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_query.expected index 4995087b1956e..a4002840f889d 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_query.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_query.expected @@ -47,6 +47,7 @@ query nestedAbstractTypeQuery { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_selection_on_inline_fragment_without_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_selection_on_inline_fragment_without_type.expected index dec9f8e17d3bd..a4a8f30dd9ecf 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_selection_on_inline_fragment_without_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_abstract_type_selection_on_inline_fragment_without_type.expected @@ -48,6 +48,7 @@ fragment nestedAbstractTypeSelectionOnInlineFragmentWithoutTypeFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } @@ -69,6 +70,7 @@ fragment nestedAbstractTypeSelectionOnInlineFragmentWithoutTypeFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_condition_on_inline_fragment_on_interface.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_condition_on_inline_fragment_on_interface.expected index 75889c9bbbb6d..28abf23bb3d98 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_condition_on_inline_fragment_on_interface.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_condition_on_inline_fragment_on_interface.expected @@ -45,6 +45,7 @@ fragment nestedConditionOnInlineFragmentOnInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_fragment_spread_on_abstract_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_fragment_spread_on_abstract_type.expected index 19a947bbd80f5..ee34d503aeb97 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_fragment_spread_on_abstract_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/nested_fragment_spread_on_abstract_type.expected @@ -49,6 +49,7 @@ fragment nestedFragmentSpreadOnAbstractTypeFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } @@ -77,6 +78,7 @@ query nestedFragmentSpreadOnAbstractTypeQuery { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/plural_fragment_on_abstract_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/plural_fragment_on_abstract_type.expected index 8ebdee1246ce1..33243d1979b61 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/plural_fragment_on_abstract_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/plural_fragment_on_abstract_type.expected @@ -38,6 +38,7 @@ fragment pluralFragmentOnAbstractTypeFragment on Cat @relay(plural: true) { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_interface.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_interface.expected index c5f47391ec689..e077f92b61423 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_interface.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_interface.expected @@ -32,6 +32,7 @@ fragment resolverFieldOnClientInterfaceFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_type_implementing_server_interface.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_type_implementing_server_interface.expected index b0d07ea933c12..8a35c27417b38 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_type_implementing_server_interface.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/resolver_field_on_client_type_implementing_server_interface.expected @@ -41,6 +41,7 @@ fragment resolverFieldOnClientTypeImplementingServerInterfaceFragment on FeedUni # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_into_interface_on_concrete_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_into_interface_on_concrete_type.expected index 00597867757cc..573411850f3ed 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_into_interface_on_concrete_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_into_interface_on_concrete_type.expected @@ -45,6 +45,7 @@ fragment spreadFragmentIntoInterfaceOnConcreteTypeFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_on_abstract_type.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_on_abstract_type.expected index dbd1d1ceb6fb7..8de26f4035500 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_on_abstract_type.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/spread_fragment_on_abstract_type.expected @@ -43,6 +43,7 @@ fragment spreadFragmentOnAbstractTypeFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/union_types_are_skipped.expected b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/union_types_are_skipped.expected index dab8e4a969de3..3b60045d1a6e8 100644 --- a/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/union_types_are_skipped.expected +++ b/compiler/crates/relay-transforms/tests/relay_resolvers_abstract_types/fixtures/union_types_are_skipped.expected @@ -36,6 +36,7 @@ fragment spreadFragmentOnAbstractTypeFragment on Cat { # output_type_info: Legacy, # fragment_data_injection_mode: None, # type_confirmed: false, + # resolver_type: ResolverModule, # } } diff --git a/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selection-skip-true.expected b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selection-skip-true.expected new file mode 100644 index 0000000000000..87920f6d75999 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selection-skip-true.expected @@ -0,0 +1,19 @@ +==================================== INPUT ==================================== +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment + } +} + +fragment Fragment on User { + lastName @skip(if: true) +} +==================================== ERROR ==================================== +✖︎ After applying transforms to the query `EmptyQuery` selections of the `EmptyQuery` that would be sent to the server are empty. This is likely due to the use of `@skip`/`@include` directives with constant values that remove all selections in the query. + + empty-selection-skip-true.graphql:2:7 + 1 │ # expected-to-throw + 2 │ query EmptyQuery($id: ID!) { + │ ^^^^^^^^^^ + 3 │ node(id: $id) { diff --git a/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selection-skip-true.graphql b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selection-skip-true.graphql new file mode 100644 index 0000000000000..85e9321f798dd --- /dev/null +++ b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selection-skip-true.graphql @@ -0,0 +1,10 @@ +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment + } +} + +fragment Fragment on User { + lastName @skip(if: true) +} \ No newline at end of file diff --git a/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selectoin-include-false.expected b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selectoin-include-false.expected new file mode 100644 index 0000000000000..0947b852580eb --- /dev/null +++ b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selectoin-include-false.expected @@ -0,0 +1,19 @@ +==================================== INPUT ==================================== +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment + } +} + +fragment Fragment on User { + lastName @include(if: false) +} +==================================== ERROR ==================================== +✖︎ After applying transforms to the query `EmptyQuery` selections of the `EmptyQuery` that would be sent to the server are empty. This is likely due to the use of `@skip`/`@include` directives with constant values that remove all selections in the query. + + empty-selectoin-include-false.graphql:2:7 + 1 │ # expected-to-throw + 2 │ query EmptyQuery($id: ID!) { + │ ^^^^^^^^^^ + 3 │ node(id: $id) { diff --git a/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selectoin-include-false.graphql b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selectoin-include-false.graphql new file mode 100644 index 0000000000000..efac3628e1f9c --- /dev/null +++ b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes/fixtures/empty-selectoin-include-false.graphql @@ -0,0 +1,10 @@ +# expected-to-throw +query EmptyQuery($id: ID!) { + node(id: $id) { + ...Fragment + } +} + +fragment Fragment on User { + lastName @include(if: false) +} diff --git a/compiler/crates/relay-transforms/tests/skip_unreachable_nodes_test.rs b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes_test.rs index 2b2ab44cc418b..223e1f10056ca 100644 --- a/compiler/crates/relay-transforms/tests/skip_unreachable_nodes_test.rs +++ b/compiler/crates/relay-transforms/tests/skip_unreachable_nodes_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<256a993c631a9ebc61e38ac8a97f397a>> + * @generated SignedSource<<39dd352e5adf4e9487dc822994bb7306>> */ mod skip_unreachable_nodes; @@ -12,6 +12,20 @@ mod skip_unreachable_nodes; use skip_unreachable_nodes::transform_fixture; use fixture_tests::test_fixture; +#[tokio::test] +async fn empty_selection_skip_true() { + let input = include_str!("skip_unreachable_nodes/fixtures/empty-selection-skip-true.graphql"); + let expected = include_str!("skip_unreachable_nodes/fixtures/empty-selection-skip-true.expected"); + test_fixture(transform_fixture, file!(), "empty-selection-skip-true.graphql", "skip_unreachable_nodes/fixtures/empty-selection-skip-true.expected", input, expected).await; +} + +#[tokio::test] +async fn empty_selectoin_include_false() { + let input = include_str!("skip_unreachable_nodes/fixtures/empty-selectoin-include-false.graphql"); + let expected = include_str!("skip_unreachable_nodes/fixtures/empty-selectoin-include-false.expected"); + test_fixture(transform_fixture, file!(), "empty-selectoin-include-false.graphql", "skip_unreachable_nodes/fixtures/empty-selectoin-include-false.expected", input, expected).await; +} + #[tokio::test] async fn keeps_other_fields() { let input = include_str!("skip_unreachable_nodes/fixtures/keeps-other-fields.graphql"); diff --git a/compiler/crates/relay-transforms/tests/updatable_directive/fixtures/dangerously-unaliased-allowed.expected b/compiler/crates/relay-transforms/tests/updatable_directive/fixtures/dangerously-unaliased-allowed.expected new file mode 100644 index 0000000000000..36363b4300ecd --- /dev/null +++ b/compiler/crates/relay-transforms/tests/updatable_directive/fixtures/dangerously-unaliased-allowed.expected @@ -0,0 +1,12 @@ +==================================== INPUT ==================================== +query TestQuery @updatable { + node(id: 4) { + ...FragmentOnUser @dangerously_unaliased_fixme + } +} + +fragment FragmentOnUser on User @assignable { + __typename +} +==================================== OUTPUT =================================== +OK diff --git a/compiler/crates/relay-transforms/tests/updatable_directive/fixtures/dangerously-unaliased-allowed.graphql b/compiler/crates/relay-transforms/tests/updatable_directive/fixtures/dangerously-unaliased-allowed.graphql new file mode 100644 index 0000000000000..70372e457e150 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/updatable_directive/fixtures/dangerously-unaliased-allowed.graphql @@ -0,0 +1,9 @@ +query TestQuery @updatable { + node(id: 4) { + ...FragmentOnUser @dangerously_unaliased_fixme + } +} + +fragment FragmentOnUser on User @assignable { + __typename +} diff --git a/compiler/crates/relay-transforms/tests/updatable_directive_test.rs b/compiler/crates/relay-transforms/tests/updatable_directive_test.rs index de7d40afb6de1..20bbfff12dafd 100644 --- a/compiler/crates/relay-transforms/tests/updatable_directive_test.rs +++ b/compiler/crates/relay-transforms/tests/updatable_directive_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<97d52b0fa84f80726d7eb06310a18c0d>> + * @generated SignedSource<<424418c51b45b6086d00947be17a05cd>> */ mod updatable_directive; @@ -33,6 +33,13 @@ async fn client_side_updatable() { test_fixture(transform_fixture, file!(), "client-side-updatable.graphql", "updatable_directive/fixtures/client-side-updatable.expected", input, expected).await; } +#[tokio::test] +async fn dangerously_unaliased_allowed() { + let input = include_str!("updatable_directive/fixtures/dangerously-unaliased-allowed.graphql"); + let expected = include_str!("updatable_directive/fixtures/dangerously-unaliased-allowed.expected"); + test_fixture(transform_fixture, file!(), "dangerously-unaliased-allowed.graphql", "updatable_directive/fixtures/dangerously-unaliased-allowed.expected", input, expected).await; +} + #[tokio::test] async fn directive_fragment_spread_invalid() { let input = include_str!("updatable_directive/fixtures/directive-fragment-spread.invalid.graphql"); diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch.rs b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch.rs new file mode 100644 index 0000000000000..cb3485badd627 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch.rs @@ -0,0 +1,36 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +use std::sync::Arc; + +use common::SourceLocationKey; +use fixture_tests::Fixture; +use graphql_ir::build; +use graphql_ir::Program; +use graphql_syntax::parse_executable; +use graphql_test_helpers::diagnostics_to_sorted_string; +use relay_test_schema::get_test_schema_with_extensions; +use relay_transforms::validate_client_schema_extensions_use_catch; + +pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result { + let parts: Vec<_> = fixture.content.split("%extensions%").collect(); + + if let [base, extensions] = parts.as_slice() { + let source_location = SourceLocationKey::standalone(fixture.file_name); + let ast = parse_executable(base, source_location).unwrap(); + let schema = get_test_schema_with_extensions(extensions); + + let ir = build(&schema, &ast.definitions).unwrap(); + let program: Program = Program::from_definitions(Arc::clone(&schema), ir); + validate_client_schema_extensions_use_catch(&program) + .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?; + + Ok("OK".to_string()) + } else { + panic!("Expected exactly one %extensions% section marker.") + } +} diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.expected b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.expected new file mode 100644 index 0000000000000..119e427cb24c4 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.expected @@ -0,0 +1,8 @@ +==================================== INPUT ==================================== +query MyQuery @throwOnFieldError { + __id +} + +# %extensions% +==================================== OUTPUT =================================== +OK diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.graphql b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.graphql new file mode 100644 index 0000000000000..940aad2db681f --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.graphql @@ -0,0 +1,5 @@ +query MyQuery @throwOnFieldError { + __id +} + +# %extensions% diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.expected b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.expected new file mode 100644 index 0000000000000..1db3ae2d173ba --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.expected @@ -0,0 +1,12 @@ +==================================== INPUT ==================================== +query MyQuery @throwOnFieldError { + client_field @catch +} + +# %extensions% + +extend type Query { + client_field: String +} +==================================== OUTPUT =================================== +OK diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.graphql b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.graphql new file mode 100644 index 0000000000000..415a11d6ae4cb --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.graphql @@ -0,0 +1,9 @@ +query MyQuery @throwOnFieldError { + client_field @catch +} + +# %extensions% + +extend type Query { + client_field: String +} diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.expected b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.expected new file mode 100644 index 0000000000000..ce109a3eaa2ef --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.expected @@ -0,0 +1,14 @@ +==================================== INPUT ==================================== +query MyQuery @throwOnFieldError { + ... @catch @alias(as: "my_alias") { + client_field + } +} + +# %extensions% + +extend type Query { + client_field: String +} +==================================== OUTPUT =================================== +OK diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.graphql b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.graphql new file mode 100644 index 0000000000000..b77d5763045e8 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.graphql @@ -0,0 +1,11 @@ +query MyQuery @throwOnFieldError { + ... @catch @alias(as: "my_alias") { + client_field + } +} + +# %extensions% + +extend type Query { + client_field: String +} diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.expected b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.expected new file mode 100644 index 0000000000000..8b27fbfcf27da --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.expected @@ -0,0 +1,14 @@ +==================================== INPUT ==================================== +query MyQuery @throwOnFieldError { + me @catch { + client_field + } +} + +# %extensions% + +extend type User { + client_field: String +} +==================================== OUTPUT =================================== +OK diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.graphql b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.graphql new file mode 100644 index 0000000000000..dce482e9c3086 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.graphql @@ -0,0 +1,11 @@ +query MyQuery @throwOnFieldError { + me @catch { + client_field + } +} + +# %extensions% + +extend type User { + client_field: String +} diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.expected b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.expected new file mode 100644 index 0000000000000..e9b8d9fbbd323 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.expected @@ -0,0 +1,19 @@ +==================================== INPUT ==================================== +# expected-to-throw +query MyQuery @throwOnFieldError { + client_field +} + +# %extensions% + +extend type Query { + client_field: String +} +==================================== ERROR ==================================== +✖︎ Expected client-defined field within `@throwOnFieldError` to be annotated with `@catch`. Accessing an unset field is treated as a field error, but Relay cannot guarantee that client field will be set before they are read. Add `@catch` to explicitly handle the case where the field is unset. + + client_field_without_catch.graphql:3:3 + 2 │ query MyQuery @throwOnFieldError { + 3 │ client_field + │ ^^^^^^^^^^^^ + 4 │ } diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.graphql b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.graphql new file mode 100644 index 0000000000000..a4fa093e409f8 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.graphql @@ -0,0 +1,10 @@ +# expected-to-throw +query MyQuery @throwOnFieldError { + client_field +} + +# %extensions% + +extend type Query { + client_field: String +} diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.expected b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.expected new file mode 100644 index 0000000000000..c668a9fefe9ce --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.expected @@ -0,0 +1,21 @@ +==================================== INPUT ==================================== +# expected-to-throw +query MyQuery @throwOnFieldError { + client_field { + name + } +} + +# %extensions% + +extend type Query { + client_field: User +} +==================================== ERROR ==================================== +✖︎ Expected client-defined field within `@throwOnFieldError` to be annotated with `@catch`. Accessing an unset field is treated as a field error, but Relay cannot guarantee that client field will be set before they are read. Add `@catch` to explicitly handle the case where the field is unset. + + client_linked_field_without_catch.graphql:3:3 + 2 │ query MyQuery @throwOnFieldError { + 3 │ client_field { + │ ^^^^^^^^^^^^ + 4 │ name diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.graphql b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.graphql new file mode 100644 index 0000000000000..04c877c19765c --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.graphql @@ -0,0 +1,12 @@ +# expected-to-throw +query MyQuery @throwOnFieldError { + client_field { + name + } +} + +# %extensions% + +extend type Query { + client_field: User +} diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.expected b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.expected new file mode 100644 index 0000000000000..951164924ba3f --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.expected @@ -0,0 +1,12 @@ +==================================== INPUT ==================================== +query MyQuery @throwOnFieldError { + client_field @catch +} + +# %extensions% + +extend type Query { + client_field: String! +} +==================================== OUTPUT =================================== +OK diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.graphql b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.graphql new file mode 100644 index 0000000000000..7afcf45a178fc --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.graphql @@ -0,0 +1,9 @@ +query MyQuery @throwOnFieldError { + client_field @catch +} + +# %extensions% + +extend type Query { + client_field: String! +} diff --git a/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch_test.rs b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch_test.rs new file mode 100644 index 0000000000000..8b368b5431ad4 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_client_schema_extensions_use_catch_test.rs @@ -0,0 +1,62 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + */ + +mod validate_client_schema_extensions_use_catch; + +use validate_client_schema_extensions_use_catch::transform_fixture; +use fixture_tests::test_fixture; + +#[tokio::test] +async fn built_in_field_without_catch() { + let input = include_str!("validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.graphql"); + let expected = include_str!("validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.expected"); + test_fixture(transform_fixture, file!(), "built_in_field_without_catch.graphql", "validate_client_schema_extensions_use_catch/fixtures/built_in_field_without_catch.expected", input, expected).await; +} + +#[tokio::test] +async fn client_field_with_catch() { + let input = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.graphql"); + let expected = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.expected"); + test_fixture(transform_fixture, file!(), "client_field_with_catch.graphql", "validate_client_schema_extensions_use_catch/fixtures/client_field_with_catch.expected", input, expected).await; +} + +#[tokio::test] +async fn client_field_with_inline_fragment_alias_with_catch() { + let input = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.graphql"); + let expected = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.expected"); + test_fixture(transform_fixture, file!(), "client_field_with_inline_fragment_alias_with_catch.graphql", "validate_client_schema_extensions_use_catch/fixtures/client_field_with_inline_fragment_alias_with_catch.expected", input, expected).await; +} + +#[tokio::test] +async fn client_field_within_catch() { + let input = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.graphql"); + let expected = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.expected"); + test_fixture(transform_fixture, file!(), "client_field_within_catch.graphql", "validate_client_schema_extensions_use_catch/fixtures/client_field_within_catch.expected", input, expected).await; +} + +#[tokio::test] +async fn client_field_without_catch() { + let input = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.graphql"); + let expected = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.expected"); + test_fixture(transform_fixture, file!(), "client_field_without_catch.graphql", "validate_client_schema_extensions_use_catch/fixtures/client_field_without_catch.expected", input, expected).await; +} + +#[tokio::test] +async fn client_linked_field_without_catch() { + let input = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.graphql"); + let expected = include_str!("validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.expected"); + test_fixture(transform_fixture, file!(), "client_linked_field_without_catch.graphql", "validate_client_schema_extensions_use_catch/fixtures/client_linked_field_without_catch.expected", input, expected).await; +} + +#[tokio::test] +async fn non_nullable_client_field_with_catch() { + let input = include_str!("validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.graphql"); + let expected = include_str!("validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.expected"); + test_fixture(transform_fixture, file!(), "non_nullable_client_field_with_catch.graphql", "validate_client_schema_extensions_use_catch/fixtures/non_nullable_client_field_with_catch.expected", input, expected).await; +} diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables.rs b/compiler/crates/relay-transforms/tests/validate_unused_variables.rs index e7e7716a9a442..2886e8762bdd9 100644 --- a/compiler/crates/relay-transforms/tests/validate_unused_variables.rs +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables.rs @@ -10,11 +10,14 @@ use std::sync::Arc; use common::SourceLocationKey; use fixture_tests::Fixture; use graphql_ir::build; +use graphql_ir::reexport::string_key::Lookup; use graphql_ir::Program; +use graphql_ir::Validator; use graphql_syntax::parse_executable; use graphql_test_helpers::diagnostics_to_sorted_string; use relay_test_schema::TEST_SCHEMA; -use relay_transforms::validate_unused_variables; +use relay_transforms::ValidateUnusedVariables; +use relay_transforms::VariableMapEntry; pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result { let source_location = SourceLocationKey::standalone(fixture.file_name); @@ -24,8 +27,36 @@ pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?; let program = Program::from_definitions(Arc::clone(&TEST_SCHEMA), ir); - validate_unused_variables(&program) - .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?; + let mut validator = ValidateUnusedVariables::new(&program); + let result = validator.validate_program(&program); + result.map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?; + + // If we didn't error, print out the state of the fragment cache so we can + // validate which entries get populated. + let mut lines = validator + .visitor + .visited_fragments + .iter() + .map(|(name, variables_entry)| match variables_entry { + VariableMapEntry::Pending => format!("{} -> PENDING", name), + VariableMapEntry::Populated(variables) => { + let mut variables_string = variables + .keys() + .map(|key| key.0.lookup()) + .collect::>(); + + variables_string.sort(); + + format!("{} -> POPULATED ({:?})", name, variables_string.join(", ")) + } + }) + .collect::>(); + + lines.sort(); - Ok("OK".to_owned()) + if lines.is_empty() { + Ok("OK.\n\nNo Cached Fragments.".to_string()) + } else { + Ok(format!("OK.\n\nCached Fragments:\n{}", lines.join("\n"))) + } } diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.expected b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.expected new file mode 100644 index 0000000000000..227562610dc61 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.expected @@ -0,0 +1,33 @@ +==================================== INPUT ==================================== +# Ensures cycles don't result in us caching incomplete used variables for a +# fragment which then gets reused by another query. + +fragment FragmentC on User { + url(relative: true, site: $varX) + nearest_neighbor { + ...FragmentD + } +} + +fragment FragmentD on User { + url(relative: true, site: $varY) + ...FragmentC +} + +query QueryA($varX: String, $varY: String) { + me { + ...FragmentC + } +} + +query QueryB($varX: String, $varY: String) { + me { + ...FragmentD + } +} +==================================== OUTPUT =================================== +OK. + +Cached Fragments: +FragmentC -> POPULATED ("varX, varY") +FragmentD -> POPULATED ("varX, varY") diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.graphql b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.graphql new file mode 100644 index 0000000000000..f69e6ca8b5e65 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.graphql @@ -0,0 +1,26 @@ +# Ensures cycles don't result in us caching incomplete used variables for a +# fragment which then gets reused by another query. + +fragment FragmentC on User { + url(relative: true, site: $varX) + nearest_neighbor { + ...FragmentD + } +} + +fragment FragmentD on User { + url(relative: true, site: $varY) + ...FragmentC +} + +query QueryA($varX: String, $varY: String) { + me { + ...FragmentC + } +} + +query QueryB($varX: String, $varY: String) { + me { + ...FragmentD + } +} diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/fragment-with-root-arguments.expected b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/fragment-with-root-arguments.expected index 64d4277d4c209..b8af49bb37029 100644 --- a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/fragment-with-root-arguments.expected +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/fragment-with-root-arguments.expected @@ -15,4 +15,6 @@ query QueryWithCondition($shouldIncludeName: Boolean!) { } } ==================================== OUTPUT =================================== -OK +OK. + +No Cached Fragments. diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/practically-unused-but-actually-used-variables.expected b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/practically-unused-but-actually-used-variables.expected index 46dccb465abd1..80e79fbabbfcd 100644 --- a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/practically-unused-but-actually-used-variables.expected +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/practically-unused-but-actually-used-variables.expected @@ -24,4 +24,7 @@ fragment ConnectionFragment on User } } ==================================== OUTPUT =================================== -OK +OK. + +Cached Fragments: +ConnectionFragment -> POPULATED ("unusedAfter, unusedFirst") diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-unused-variable-error-suppressed.expected b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-unused-variable-error-suppressed.expected index aa38771f7f4fd..ead87f895d0b3 100644 --- a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-unused-variable-error-suppressed.expected +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-unused-variable-error-suppressed.expected @@ -6,4 +6,6 @@ query QueryWithUnusedVariable($unused: ID) } } ==================================== OUTPUT =================================== -OK +OK. + +No Cached Fragments. diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-variables-shadowed-by-local-variable-and-used-as-root-variable.expected b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-variables-shadowed-by-local-variable-and-used-as-root-variable.expected index af400a5e2341e..48ef47887adfe 100644 --- a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-variables-shadowed-by-local-variable-and-used-as-root-variable.expected +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/query-with-variables-shadowed-by-local-variable-and-used-as-root-variable.expected @@ -24,4 +24,9 @@ fragment AnotherUser_data on User { } } ==================================== OUTPUT =================================== -OK +OK. + +Cached Fragments: +AnotherUser_data -> POPULATED ("foo") +User_data -> POPULATED ("foo") +User_data_with_args -> POPULATED ("foo") diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/variable-in-the-complex-object-list.expected b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/variable-in-the-complex-object-list.expected index 4e40efa352417..9ab84bdc63b2f 100644 --- a/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/variable-in-the-complex-object-list.expected +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables/fixtures/variable-in-the-complex-object-list.expected @@ -15,4 +15,6 @@ query Q2($size: Int) { } } ==================================== OUTPUT =================================== -OK +OK. + +No Cached Fragments. diff --git a/compiler/crates/relay-transforms/tests/validate_unused_variables_test.rs b/compiler/crates/relay-transforms/tests/validate_unused_variables_test.rs index 0910f691fa962..bf0e366058cd2 100644 --- a/compiler/crates/relay-transforms/tests/validate_unused_variables_test.rs +++ b/compiler/crates/relay-transforms/tests/validate_unused_variables_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2d9c78832993b2bbe4c580b22d0aeecf>> + * @generated SignedSource<<4d8584b4ed41dabea8eb7e0b80ec52a2>> */ mod validate_unused_variables; @@ -12,6 +12,13 @@ mod validate_unused_variables; use validate_unused_variables::transform_fixture; use fixture_tests::test_fixture; +#[tokio::test] +async fn cycles_read_from_different_entrypoints() { + let input = include_str!("validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.graphql"); + let expected = include_str!("validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.expected"); + test_fixture(transform_fixture, file!(), "cycles-read-from-different-entrypoints.graphql", "validate_unused_variables/fixtures/cycles-read-from-different-entrypoints.expected", input, expected).await; +} + #[tokio::test] async fn fragment_with_root_arguments() { let input = include_str!("validate_unused_variables/fixtures/fragment-with-root-arguments.graphql"); diff --git a/compiler/crates/relay-typegen/Cargo.toml b/compiler/crates/relay-typegen/Cargo.toml index 09ec8d813a6f4..31c62b6790b3b 100644 --- a/compiler/crates/relay-typegen/Cargo.toml +++ b/compiler/crates/relay-typegen/Cargo.toml @@ -21,8 +21,8 @@ graphql-ir = { path = "../graphql-ir" } graphql-syntax = { path = "../graphql-syntax" } indexmap = { version = "2.2.6", features = ["arbitrary", "rayon", "serde"] } intern = { path = "../intern" } -itertools = "0.13.0" -lazy_static = "1.4" +itertools = "0.14.0" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } relay-config = { path = "../relay-config" } relay-schema = { path = "../relay-schema" } relay-transforms = { path = "../relay-transforms" } @@ -32,7 +32,7 @@ schema = { path = "../schema" } fixture-tests = { path = "../fixture-tests" } graphql-syntax = { path = "../graphql-syntax" } graphql-test-helpers = { path = "../graphql-test-helpers" } -regex = "1.9.2" +regex = "1.11.1" relay-codegen = { path = "../relay-codegen" } relay-test-schema = { path = "../relay-test-schema" } tokio = { version = "1.41.0", features = ["full", "test-util", "tracing"] } diff --git a/compiler/crates/relay-typegen/src/visit.rs b/compiler/crates/relay-typegen/src/visit.rs index dad9e2c7b1e0c..2df28aeade4e8 100644 --- a/compiler/crates/relay-typegen/src/visit.rs +++ b/compiler/crates/relay-typegen/src/visit.rs @@ -45,6 +45,7 @@ use relay_schema::definitions::ResolverType; use relay_schema::CUSTOM_SCALAR_DIRECTIVE_NAME; use relay_schema::EXPORT_NAME_CUSTOM_SCALAR_ARGUMENT_NAME; use relay_schema::PATH_CUSTOM_SCALAR_ARGUMENT_NAME; +use relay_transforms::relay_resolvers::ResolverSchemaGenType; use relay_transforms::CatchMetadataDirective; use relay_transforms::CatchTo; use relay_transforms::ClientEdgeMetadata; @@ -641,12 +642,17 @@ fn import_relay_resolver_function_type( None => None, }; - let resolver_type = if resolver_metadata.type_confirmed + let is_property_lookup = match resolver_metadata.resolver_type { + ResolverSchemaGenType::PropertyLookup { .. } => true, + ResolverSchemaGenType::ResolverModule => false, + }; + let resolver_type = if (resolver_metadata.type_confirmed && typegen_context .project_config .feature_flags .omit_resolver_type_assertions_for_confirmed_types - .is_fully_enabled() + .is_fully_enabled()) + || is_property_lookup { None } else { @@ -665,17 +671,19 @@ fn import_relay_resolver_function_type( )) }; - let imported_resolver = ImportedResolver { - resolver_name, - resolver_type, - import_path, - context_import, - }; + if !is_property_lookup { + let imported_resolver = ImportedResolver { + resolver_name, + resolver_type, + import_path, + context_import, + }; - imported_resolvers - .0 - .entry(local_resolver_name) - .or_insert(imported_resolver); + imported_resolvers + .0 + .entry(local_resolver_name) + .or_insert(imported_resolver); + } } /// Check if the scalar field has the special type `RelayResolverValue`. This is a type that @@ -1087,6 +1095,7 @@ fn visit_actor_change( value: AST::Nullable(Box::new(AST::ActorChangePoint(Box::new( selections_to_babel( typegen_context, + &field.type_.inner(), linked_field_selections.into_iter(), MaskStatus::Masked, None, @@ -1289,6 +1298,38 @@ fn visit_scalar_field( })); } +#[allow(clippy::too_many_arguments)] +fn raw_response_visit_condition( + typegen_context: &'_ TypegenContext<'_>, + type_selections: &mut Vec, + condition: &Condition, + encountered_enums: &mut EncounteredEnums, + match_fields: &mut MatchFields, + encountered_fragments: &mut EncounteredFragments, + imported_raw_response_types: &mut ImportedRawResponseTypes, + runtime_imports: &mut RuntimeImports, + custom_scalars: &mut CustomScalarsImports, + enclosing_linked_field_concrete_type: Option, + is_throw_on_field_error: bool, +) { + let mut selections = raw_response_visit_selections( + typegen_context, + &condition.selections, + encountered_enums, + match_fields, + encountered_fragments, + imported_raw_response_types, + runtime_imports, + custom_scalars, + enclosing_linked_field_concrete_type, + is_throw_on_field_error, + ); + for selection in selections.iter_mut() { + selection.set_conditional(true); + } + type_selections.append(&mut selections); +} + #[allow(clippy::too_many_arguments)] fn visit_condition( typegen_context: &'_ TypegenContext<'_>, @@ -1330,6 +1371,7 @@ fn visit_condition( #[allow(clippy::too_many_arguments)] pub(crate) fn get_data_type( typegen_context: &'_ TypegenContext<'_>, + concrete_type: &Type, selections: impl Iterator, mask_status: MaskStatus, fragment_type_name: Option, @@ -1343,6 +1385,7 @@ pub(crate) fn get_data_type( ) -> AST { let mut data_type = selections_to_babel( typegen_context, + concrete_type, selections, mask_status, fragment_type_name, @@ -1364,6 +1407,7 @@ pub(crate) fn get_data_type( #[allow(clippy::too_many_arguments)] fn selections_to_babel( typegen_context: &'_ TypegenContext<'_>, + concrete_type: &Type, selections: impl Iterator, mask_status: MaskStatus, fragment_type_name: Option, @@ -1403,7 +1447,7 @@ fn selections_to_babel( } } - if should_emit_discriminated_union(&by_concrete_type, &base_fields) { + if should_emit_discriminated_union(concrete_type, &by_concrete_type, &base_fields) { get_discriminated_union_ast( by_concrete_type, &base_fields, @@ -1622,11 +1666,15 @@ fn get_discriminated_union_ast( /// /// If this condition passes, we emit a discriminated union fn should_emit_discriminated_union( + concrete_type: &Type, by_concrete_type: &IndexMap>, base_fields: &IndexMap, ) -> bool { - !by_concrete_type.is_empty() - && base_fields.values().all(TypeSelection::is_typename) + if by_concrete_type.is_empty() || !concrete_type.is_abstract_type() { + return false; + } + + base_fields.values().all(TypeSelection::is_typename) && (base_fields.values().any(TypeSelection::is_typename) || by_concrete_type .values() @@ -1851,6 +1899,7 @@ fn make_prop( let getter_object_props = selections_to_babel( typegen_context, + &linked_field.node_type.inner(), no_fragments.into_iter(), mask_status, None, @@ -1942,6 +1991,7 @@ fn make_prop( } else { let object_props = selections_to_babel( typegen_context, + &linked_field.node_type.inner(), hashmap_into_values(linked_field.node_selections), mask_status, None, @@ -2340,20 +2390,19 @@ pub(crate) fn raw_response_visit_selections( enclosing_linked_field_concrete_type, emit_semantic_types, ), - Selection::Condition(condition) => { - type_selections.extend(raw_response_visit_selections( - typegen_context, - &condition.selections, - encountered_enums, - match_fields, - encountered_fragments, - imported_raw_response_types, - runtime_imports, - custom_scalars, - enclosing_linked_field_concrete_type, - emit_semantic_types, - )); - } + Selection::Condition(condition) => raw_response_visit_condition( + typegen_context, + &mut type_selections, + condition, + encountered_enums, + match_fields, + encountered_fragments, + imported_raw_response_types, + runtime_imports, + custom_scalars, + enclosing_linked_field_concrete_type, + emit_semantic_types, + ), } } type_selections diff --git a/compiler/crates/relay-typegen/src/write.rs b/compiler/crates/relay-typegen/src/write.rs index 66d72c1f8e74d..d38596ca83718 100644 --- a/compiler/crates/relay-typegen/src/write.rs +++ b/compiler/crates/relay-typegen/src/write.rs @@ -139,6 +139,7 @@ pub(crate) fn write_operation_type_exports_section( let mut data_type = get_data_type( typegen_context, + &typegen_operation.type_, type_selections.into_iter(), MaskStatus::Masked, // Queries are never unmasked None, @@ -461,6 +462,7 @@ pub(crate) fn write_fragment_type_exports_section( let mut data_type = get_data_type( typegen_context, + &fragment_definition.type_condition, type_selections.into_iter(), mask_status, if mask_status == MaskStatus::Unmasked { @@ -607,12 +609,9 @@ fn write_fragment_imports( ), }; - let should_write_current_referenced_fragment = fragment_name_to_skip - .map_or(true, |fragment_name_to_skip| { - fragment_name_to_skip != current_referenced_fragment - }); - - if !should_write_current_referenced_fragment { + let should_skip_writing_current_referenced_fragment = + fragment_name_to_skip == Some(current_referenced_fragment); + if should_skip_writing_current_referenced_fragment { continue; } @@ -1111,7 +1110,7 @@ fn write_concrete_validator_function( } fn is_plural(node: &FragmentDefinition) -> bool { - RelayDirective::find(&node.directives).map_or(false, |relay_directive| relay_directive.plural) + RelayDirective::find(&node.directives).is_some_and(|relay_directive| relay_directive.plural) } fn has_fragment_spread(selections: &[Selection]) -> bool { diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/fragment-spread.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/fragment-spread.expected index 92307abaf347d..42c38439b5729 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/fragment-spread.expected +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/fragment-spread.expected @@ -113,11 +113,6 @@ declare export opaque type PageFragment$fragmentType: FragmentType; export type PageFragment$data = {| +__typename: "Page", +$fragmentType: PageFragment$fragmentType, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$fragmentType: PageFragment$fragmentType, |}; export type PageFragment$key = { +$data?: PageFragment$data, @@ -130,11 +125,6 @@ declare export opaque type PictureFragment$fragmentType: FragmentType; export type PictureFragment$data = {| +__typename: "Image", +$fragmentType: PictureFragment$fragmentType, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$fragmentType: PictureFragment$fragmentType, |}; export type PictureFragment$key = { +$data?: PictureFragment$data, @@ -147,11 +137,6 @@ declare export opaque type UserFrag1$fragmentType: FragmentType; export type UserFrag1$data = {| +__typename: "User", +$fragmentType: UserFrag1$fragmentType, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$fragmentType: UserFrag1$fragmentType, |}; export type UserFrag1$key = { +$data?: UserFrag1$data, @@ -164,11 +149,6 @@ declare export opaque type UserFrag2$fragmentType: FragmentType; export type UserFrag2$data = {| +__typename: "User", +$fragmentType: UserFrag2$fragmentType, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$fragmentType: UserFrag2$fragmentType, |}; export type UserFrag2$key = { +$data?: UserFrag2$data, diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/inline-fragment.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/inline-fragment.expected index c865e0610f83d..7758f99ae7f6c 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/inline-fragment.expected +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/inline-fragment.expected @@ -139,11 +139,6 @@ declare export opaque type SomeFragment$fragmentType: FragmentType; export type SomeFragment$data = {| +__typename: "User", +$fragmentType: SomeFragment$fragmentType, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$fragmentType: SomeFragment$fragmentType, |}; export type SomeFragment$key = { +$data?: SomeFragment$data, diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/mixed-conditonal-raw-response.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/mixed-conditonal-raw-response.expected new file mode 100644 index 0000000000000..a3f67d8970424 --- /dev/null +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/mixed-conditonal-raw-response.expected @@ -0,0 +1,176 @@ +==================================== INPUT ==================================== +query AppQuery($showEmail: Boolean!) @raw_response_type { + # Repro of the issue raised in https://github.com/facebook/relay/issues/4914 + # the `story` key should only be generated once here but it's been generated twice + ...AppFragment + ...AppConditionalFragment +} + +fragment AppFragment on Query { + story { + name + } +} + +fragment AppConditionalFragment on Query { + story @include(if: $showEmail) { + tracking + } +} + +# Query Root +query AppQuery1($showEmail: Boolean!) @raw_response_type @__debug { + story { + name + } + story @include(if: $showEmail) { + tracking + } +} + +# Inline Fragment +query AppQuery2($showEmail: Boolean!) @raw_response_type @__debug { + ... on Query { + story { + name + } + story @include(if: $showEmail) { + tracking + } + } +} + +# Condition +query AppQuery3($showEmail: Boolean!) @raw_response_type @__debug { + ... on Query @include(if: $showEmail) { + story { + name + } + story @include(if: $showEmail) { + tracking + } + } +} +==================================== OUTPUT =================================== +import type { AppConditionalFragment$fragmentType } from "AppConditionalFragment.graphql"; +import type { AppFragment$fragmentType } from "AppFragment.graphql"; +export type AppQuery$variables = {| + showEmail: CustomBoolean, +|}; +export type AppQuery$data = {| + +$fragmentSpreads: AppConditionalFragment$fragmentType & AppFragment$fragmentType, +|}; +export type AppQuery$rawResponse = {| + +story: ?{| + +id: string, + +name: ?string, + |}, + +story?: ?{| + +tracking: ?string, + |}, +|}; +export type AppQuery = {| + rawResponse: AppQuery$rawResponse, + response: AppQuery$data, + variables: AppQuery$variables, +|}; +------------------------------------------------------------------------------- +export type AppQuery1$variables = {| + showEmail: CustomBoolean, +|}; +export type AppQuery1$data = {| + +story: ?{| + +name?: ?string, + +tracking: ?string, + |}, +|}; +export type AppQuery1$rawResponse = {| + +story: ?{| + +id: string, + +name: ?string, + |}, + +story?: ?{| + +tracking: ?string, + |}, +|}; +export type AppQuery1 = {| + rawResponse: AppQuery1$rawResponse, + response: AppQuery1$data, + variables: AppQuery1$variables, +|}; +------------------------------------------------------------------------------- +export type AppQuery2$variables = {| + showEmail: CustomBoolean, +|}; +export type AppQuery2$data = {| + +story: ?{| + +name?: ?string, + +tracking: ?string, + |}, +|}; +export type AppQuery2$rawResponse = {| + +story: ?{| + +id: string, + +name: ?string, + |}, + +story?: ?{| + +tracking: ?string, + |}, +|}; +export type AppQuery2 = {| + rawResponse: AppQuery2$rawResponse, + response: AppQuery2$data, + variables: AppQuery2$variables, +|}; +------------------------------------------------------------------------------- +export type AppQuery3$variables = {| + showEmail: CustomBoolean, +|}; +export type AppQuery3$data = {| + +story?: ?{| + +name?: ?string, + +tracking: ?string, + |}, +|}; +export type AppQuery3$rawResponse = {| + +story?: ?{| + +id: string, + +name: ?string, + |}, + +story?: ?{| + +tracking: ?string, + |}, +|}; +export type AppQuery3 = {| + rawResponse: AppQuery3$rawResponse, + response: AppQuery3$data, + variables: AppQuery3$variables, +|}; +------------------------------------------------------------------------------- +import type { FragmentType } from "relay-runtime"; +declare export opaque type AppConditionalFragment$fragmentType: FragmentType; +export type AppConditionalFragment$data = {| + +story?: ?{| + +tracking: ?string, + |}, + +$fragmentType: AppConditionalFragment$fragmentType, +|}; +export type AppConditionalFragment$key = { + +$data?: AppConditionalFragment$data, + +$fragmentSpreads: AppConditionalFragment$fragmentType, + ... +}; +------------------------------------------------------------------------------- +import type { FragmentType } from "relay-runtime"; +declare export opaque type AppFragment$fragmentType: FragmentType; +export type AppFragment$data = {| + +story: ?{| + +name: ?string, + |}, + +$fragmentType: AppFragment$fragmentType, +|}; +export type AppFragment$key = { + +$data?: AppFragment$data, + +$fragmentSpreads: AppFragment$fragmentType, + ... +}; diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/mixed-conditonal-raw-response.graphql b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/mixed-conditonal-raw-response.graphql new file mode 100644 index 0000000000000..264facace2b02 --- /dev/null +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/mixed-conditonal-raw-response.graphql @@ -0,0 +1,53 @@ + +query AppQuery($showEmail: Boolean!) @raw_response_type { + # Repro of the issue raised in https://github.com/facebook/relay/issues/4914 + # the `story` key should only be generated once here but it's been generated twice + ...AppFragment + ...AppConditionalFragment +} + +fragment AppFragment on Query { + story { + name + } +} + +fragment AppConditionalFragment on Query { + story @include(if: $showEmail) { + tracking + } +} + +# Query Root +query AppQuery1($showEmail: Boolean!) @raw_response_type @__debug { + story { + name + } + story @include(if: $showEmail) { + tracking + } +} + +# Inline Fragment +query AppQuery2($showEmail: Boolean!) @raw_response_type @__debug { + ... on Query { + story { + name + } + story @include(if: $showEmail) { + tracking + } + } +} + +# Condition +query AppQuery3($showEmail: Boolean!) @raw_response_type @__debug { + ... on Query @include(if: $showEmail) { + story { + name + } + story @include(if: $showEmail) { + tracking + } + } +} diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/query-with-raw-response-on-conditional.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/query-with-raw-response-on-conditional.expected index 445990cd1e0a7..5963298259101 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/query-with-raw-response-on-conditional.expected +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/query-with-raw-response-on-conditional.expected @@ -29,13 +29,13 @@ export type ExampleQuery$data = {| export type ExampleQuery$rawResponse = {| +node: ?({| +__typename: "User", - +feedback: ?{| + +feedback?: ?{| +id: string, +name: ?string, |}, +id: string, - +lastName: ?string, - +name: ?string, + +lastName?: ?string, + +name?: ?string, |} | {| +__typename: string, +id: string, diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.expected index dbe459b6b87e4..d011c9721e97b 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.expected +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.expected @@ -5,7 +5,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -13,24 +13,18 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User!] @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser!] + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } ==================================== OUTPUT =================================== -import type { RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType } from "RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$variables = {| - id: string, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +node: ?{| - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - |}, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends = {| - response: ClientEdgeQuery_relayResolver_Query_me__best_friends$data, - variables: ClientEdgeQuery_relayResolver_Query_me__best_friends$variables, -|}; -------------------------------------------------------------------------------- import type { DataID } from "relay-runtime"; import type { relayResolver_BestFriendResolverFragment_name$key } from "relayResolver_BestFriendResolverFragment_name.graphql"; import userBestFriendsResolverType from "BestFriendResolver"; @@ -55,20 +49,6 @@ export type relayResolver_Query = {| |}; ------------------------------------------------------------------------------- import type { FragmentType } from "relay-runtime"; -declare export opaque type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType: FragmentType; -import type { ClientEdgeQuery_relayResolver_Query_me__best_friends$variables } from "ClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +id: string, - +name: ?string, - +$fragmentType: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, -|}; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$key = { - +$data?: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data, - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - ... -}; -------------------------------------------------------------------------------- -import type { FragmentType } from "relay-runtime"; declare export opaque type relayResolver_BestFriendResolverFragment_name$fragmentType: FragmentType; export type relayResolver_BestFriendResolverFragment_name$data = {| +name: ?string, diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.graphql b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.graphql index d1c5ee3543017..7c3e2e9acc1b2 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.graphql +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge-with-required-edge.graphql @@ -4,7 +4,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -12,6 +12,14 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User!] @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser!] + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.expected index 3a8df881bba83..74f55feefe7b1 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.expected +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.expected @@ -5,7 +5,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -13,24 +13,18 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User] @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser] + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } ==================================== OUTPUT =================================== -import type { RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType } from "RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$variables = {| - id: string, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +node: ?{| - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - |}, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends = {| - response: ClientEdgeQuery_relayResolver_Query_me__best_friends$data, - variables: ClientEdgeQuery_relayResolver_Query_me__best_friends$variables, -|}; -------------------------------------------------------------------------------- import type { DataID } from "relay-runtime"; import type { relayResolver_BestFriendResolverFragment_name$key } from "relayResolver_BestFriendResolverFragment_name.graphql"; import userBestFriendsResolverType from "BestFriendResolver"; @@ -55,20 +49,6 @@ export type relayResolver_Query = {| |}; ------------------------------------------------------------------------------- import type { FragmentType } from "relay-runtime"; -declare export opaque type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType: FragmentType; -import type { ClientEdgeQuery_relayResolver_Query_me__best_friends$variables } from "ClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +id: string, - +name: ?string, - +$fragmentType: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, -|}; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$key = { - +$data?: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data, - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - ... -}; -------------------------------------------------------------------------------- -import type { FragmentType } from "relay-runtime"; declare export opaque type relayResolver_BestFriendResolverFragment_name$fragmentType: FragmentType; export type relayResolver_BestFriendResolverFragment_name$data = {| +name: ?string, diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.graphql b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.graphql index 63c02afd5ec52..db0ebd4589fe7 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.graphql +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-client-edge.graphql @@ -4,7 +4,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -12,6 +12,14 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User] @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser] + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.expected index d0f9898a42683..8b5a2986dea14 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.expected +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.expected @@ -5,7 +5,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -13,24 +13,18 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User!]! @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser!]! + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } ==================================== OUTPUT =================================== -import type { RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType } from "RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$variables = {| - id: string, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +node: ?{| - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - |}, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends = {| - response: ClientEdgeQuery_relayResolver_Query_me__best_friends$data, - variables: ClientEdgeQuery_relayResolver_Query_me__best_friends$variables, -|}; -------------------------------------------------------------------------------- import type { DataID } from "relay-runtime"; import type { relayResolver_BestFriendResolverFragment_name$key } from "relayResolver_BestFriendResolverFragment_name.graphql"; import userBestFriendsResolverType from "BestFriendResolver"; @@ -55,20 +49,6 @@ export type relayResolver_Query = {| |}; ------------------------------------------------------------------------------- import type { FragmentType } from "relay-runtime"; -declare export opaque type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType: FragmentType; -import type { ClientEdgeQuery_relayResolver_Query_me__best_friends$variables } from "ClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +id: string, - +name: ?string, - +$fragmentType: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, -|}; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$key = { - +$data?: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data, - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - ... -}; -------------------------------------------------------------------------------- -import type { FragmentType } from "relay-runtime"; declare export opaque type relayResolver_BestFriendResolverFragment_name$fragmentType: FragmentType; export type relayResolver_BestFriendResolverFragment_name$data = {| +name: ?string, diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.graphql b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.graphql index ac9752b4046f4..e3a2bb6f955ba 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.graphql +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge-with-required-edge.graphql @@ -4,7 +4,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -12,6 +12,14 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User!]! @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser!]! + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.expected b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.expected index 84956e9fc5a43..26161ef29372b 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.expected +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.expected @@ -5,7 +5,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -13,24 +13,18 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User]! @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser]! + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } ==================================== OUTPUT =================================== -import type { RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType } from "RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$variables = {| - id: string, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +node: ?{| - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - |}, -|}; -export type ClientEdgeQuery_relayResolver_Query_me__best_friends = {| - response: ClientEdgeQuery_relayResolver_Query_me__best_friends$data, - variables: ClientEdgeQuery_relayResolver_Query_me__best_friends$variables, -|}; -------------------------------------------------------------------------------- import type { DataID } from "relay-runtime"; import type { relayResolver_BestFriendResolverFragment_name$key } from "relayResolver_BestFriendResolverFragment_name.graphql"; import userBestFriendsResolverType from "BestFriendResolver"; @@ -55,20 +49,6 @@ export type relayResolver_Query = {| |}; ------------------------------------------------------------------------------- import type { FragmentType } from "relay-runtime"; -declare export opaque type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType: FragmentType; -import type { ClientEdgeQuery_relayResolver_Query_me__best_friends$variables } from "ClientEdgeQuery_relayResolver_Query_me__best_friends.graphql"; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data = {| - +id: string, - +name: ?string, - +$fragmentType: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, -|}; -export type RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$key = { - +$data?: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$data, - +$fragmentSpreads: RefetchableClientEdgeQuery_relayResolver_Query_me__best_friends$fragmentType, - ... -}; -------------------------------------------------------------------------------- -import type { FragmentType } from "relay-runtime"; declare export opaque type relayResolver_BestFriendResolverFragment_name$fragmentType: FragmentType; export type relayResolver_BestFriendResolverFragment_name$data = {| +name: ?string, diff --git a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.graphql b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.graphql index 2151c70bc603b..dd5ce21d14303 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.graphql +++ b/compiler/crates/relay-typegen/tests/generate_flow/fixtures/relay-resolver-plural-required-client-edge.graphql @@ -4,7 +4,7 @@ fragment relayResolver_BestFriendResolverFragment_name on User { query relayResolver_Query { me { - best_friends @waterfall { + best_friends { name } } @@ -12,6 +12,14 @@ query relayResolver_Query { # %extensions% +type ClientUser { + name: String +} + extend type User { - best_friends: [User]! @relay_resolver(fragment_name: "relayResolver_BestFriendResolverFragment_name", import_path: "./foo/bar/baz/BestFriendResolver.js") + best_friends: [ClientUser]! + @relay_resolver( + fragment_name: "relayResolver_BestFriendResolverFragment_name" + import_path: "./foo/bar/baz/BestFriendResolver.js" + ) } diff --git a/compiler/crates/relay-typegen/tests/generate_flow_test.rs b/compiler/crates/relay-typegen/tests/generate_flow_test.rs index 43804434c77d7..b4413c90c643c 100644 --- a/compiler/crates/relay-typegen/tests/generate_flow_test.rs +++ b/compiler/crates/relay-typegen/tests/generate_flow_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<7c4bbd43433461799f4caf7a6320fa4e>> + * @generated SignedSource<<1362eec89123512c826effa9bf3a99ec>> */ mod generate_flow; @@ -271,6 +271,13 @@ async fn match_field_in_query() { test_fixture(transform_fixture, file!(), "match-field-in-query.graphql", "generate_flow/fixtures/match-field-in-query.expected", input, expected).await; } +#[tokio::test] +async fn mixed_conditonal_raw_response() { + let input = include_str!("generate_flow/fixtures/mixed-conditonal-raw-response.graphql"); + let expected = include_str!("generate_flow/fixtures/mixed-conditonal-raw-response.expected"); + test_fixture(transform_fixture, file!(), "mixed-conditonal-raw-response.graphql", "generate_flow/fixtures/mixed-conditonal-raw-response.expected", input, expected).await; +} + #[tokio::test] async fn mutation() { let input = include_str!("generate_flow/fixtures/mutation.graphql"); diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/fragment-spread.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/fragment-spread.expected index c97ede67cd471..29e06b56fab8d 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/fragment-spread.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/fragment-spread.expected @@ -101,11 +101,6 @@ import { FragmentRefs } from "relay-runtime"; export type PageFragment$data = { readonly __typename: "Page"; readonly " $fragmentType": "PageFragment"; -} | { - // This will never be '%other', but we need some - // value in case none of the concrete values match. - readonly __typename: "%other"; - readonly " $fragmentType": "PageFragment"; }; export type PageFragment$key = { readonly " $data"?: PageFragment$data; @@ -116,11 +111,6 @@ import { FragmentRefs } from "relay-runtime"; export type PictureFragment$data = { readonly __typename: "Image"; readonly " $fragmentType": "PictureFragment"; -} | { - // This will never be '%other', but we need some - // value in case none of the concrete values match. - readonly __typename: "%other"; - readonly " $fragmentType": "PictureFragment"; }; export type PictureFragment$key = { readonly " $data"?: PictureFragment$data; @@ -131,11 +121,6 @@ import { FragmentRefs } from "relay-runtime"; export type UserFrag1$data = { readonly __typename: "User"; readonly " $fragmentType": "UserFrag1"; -} | { - // This will never be '%other', but we need some - // value in case none of the concrete values match. - readonly __typename: "%other"; - readonly " $fragmentType": "UserFrag1"; }; export type UserFrag1$key = { readonly " $data"?: UserFrag1$data; @@ -146,11 +131,6 @@ import { FragmentRefs } from "relay-runtime"; export type UserFrag2$data = { readonly __typename: "User"; readonly " $fragmentType": "UserFrag2"; -} | { - // This will never be '%other', but we need some - // value in case none of the concrete values match. - readonly __typename: "%other"; - readonly " $fragmentType": "UserFrag2"; }; export type UserFrag2$key = { readonly " $data"?: UserFrag2$data; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/inline-fragment.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/inline-fragment.expected index a68de1296e88c..7b07ca864fe6b 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/inline-fragment.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/inline-fragment.expected @@ -129,11 +129,6 @@ import { FragmentRefs } from "relay-runtime"; export type SomeFragment$data = { readonly __typename: "User"; readonly " $fragmentType": "SomeFragment"; -} | { - // This will never be '%other', but we need some - // value in case none of the concrete values match. - readonly __typename: "%other"; - readonly " $fragmentType": "SomeFragment"; }; export type SomeFragment$key = { readonly " $data"?: SomeFragment$data; diff --git a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/query-with-raw-response-on-conditional.expected b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/query-with-raw-response-on-conditional.expected index 777565655be7b..4cd30d9a68dc7 100644 --- a/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/query-with-raw-response-on-conditional.expected +++ b/compiler/crates/relay-typegen/tests/generate_typescript/fixtures/query-with-raw-response-on-conditional.expected @@ -29,13 +29,13 @@ export type ExampleQuery$data = { export type ExampleQuery$rawResponse = { readonly node: { readonly __typename: "User"; - readonly feedback: { + readonly feedback?: { readonly id: string; readonly name: string | null | undefined; } | null | undefined; readonly id: string; - readonly lastName: string | null | undefined; - readonly name: string | null | undefined; + readonly lastName?: string | null | undefined; + readonly name?: string | null | undefined; } | { readonly __typename: string; readonly id: string; diff --git a/compiler/crates/resolution-path/src/lib.rs b/compiler/crates/resolution-path/src/lib.rs index 05c3b9743368c..f91683f92574e 100644 --- a/compiler/crates/resolution-path/src/lib.rs +++ b/compiler/crates/resolution-path/src/lib.rs @@ -188,7 +188,7 @@ pub trait ResolvePosition<'a>: Sized { type Parent; fn resolve(&'a self, parent: Self::Parent, position: Span) -> ResolutionPath<'a>; fn contains(&'a self, position: Span) -> bool; - fn path(&'a self, parent: Self::Parent) -> Path<&Self, Self::Parent> { + fn path(&'a self, parent: Self::Parent) -> Path<&'a Self, Self::Parent> { Path { inner: self, parent, diff --git a/compiler/crates/schema-diff/Cargo.toml b/compiler/crates/schema-diff/Cargo.toml index 921d92ceb5eba..af025541c2e82 100644 --- a/compiler/crates/schema-diff/Cargo.toml +++ b/compiler/crates/schema-diff/Cargo.toml @@ -17,7 +17,7 @@ common = { path = "../common" } fnv = "1.0" graphql-syntax = { path = "../graphql-syntax" } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } relay-config = { path = "../relay-config" } -rustc-hash = "1.1.0" +rustc-hash = "2.1.0" schema = { path = "../schema" } diff --git a/compiler/crates/schema-extractor/Cargo.toml b/compiler/crates/schema-extractor/Cargo.toml index ee5a3b4ecc69b..4059465ab4b57 100644 --- a/compiler/crates/schema-extractor/Cargo.toml +++ b/compiler/crates/schema-extractor/Cargo.toml @@ -14,6 +14,6 @@ hermes_comments = { git = "https://github.com/facebook/hermes.git" } hermes_estree = { git = "https://github.com/facebook/hermes.git" } hermes_parser = { git = "https://github.com/facebook/hermes.git" } intern = { path = "../intern" } -rustc-hash = "1.1.0" +rustc-hash = "2.1.0" serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" diff --git a/compiler/crates/schema-flatbuffer/generate_flatbuffer.py b/compiler/crates/schema-flatbuffer/generate_flatbuffer.py index 3cfa703afab50..0cde77e76614b 100755 --- a/compiler/crates/schema-flatbuffer/generate_flatbuffer.py +++ b/compiler/crates/schema-flatbuffer/generate_flatbuffer.py @@ -42,9 +42,7 @@ * * \x40generated */ -""".format( - flatc_version -) +""".format(flatc_version) content = content.replace(old_header, new_header) diff --git a/compiler/crates/schema-print/Cargo.toml b/compiler/crates/schema-print/Cargo.toml index 7939af1914afe..718c789ea86ed 100644 --- a/compiler/crates/schema-print/Cargo.toml +++ b/compiler/crates/schema-print/Cargo.toml @@ -23,7 +23,7 @@ path = "tests/print_schema_test.rs" [dependencies] fnv = "1.0" intern = { path = "../intern" } -itertools = "0.13.0" +itertools = "0.14.0" rayon = "1.9.0" schema = { path = "../schema" } diff --git a/compiler/crates/schema-validate/Cargo.toml b/compiler/crates/schema-validate/Cargo.toml index cdbd1a62b35bb..0c2bc84459784 100644 --- a/compiler/crates/schema-validate/Cargo.toml +++ b/compiler/crates/schema-validate/Cargo.toml @@ -17,17 +17,17 @@ name = "schema_validate_test" path = "tests/validate_schema_test.rs" [dependencies] -clap = { version = "4.5.20", features = ["derive", "env", "string", "unicode", "wrap_help"] } +clap = { version = "4.5.30", features = ["derive", "env", "string", "unicode", "wrap_help"] } common = { path = "../common" } fnv = "1.0" graphql-cli = { path = "../graphql-cli" } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } rayon = "1.9.0" -regex = "1.9.2" +regex = "1.11.1" schema = { path = "../schema" } serde = { version = "1.0.185", features = ["derive", "rc"] } -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] fixture-tests = { path = "../fixture-tests" } diff --git a/compiler/crates/schema-validate/src/main.rs b/compiler/crates/schema-validate/src/main.rs index b6b09d9f79472..ddcd93eaea2a8 100644 --- a/compiler/crates/schema-validate/src/main.rs +++ b/compiler/crates/schema-validate/src/main.rs @@ -61,7 +61,7 @@ fn build_schema_from_path(schema_file: &str) -> DiagnosticsResult { let path = Path::new(schema_file); let extensions: &[(&str, SourceLocationKey)] = &[]; - return if path.is_file() { + if path.is_file() { build_schema_with_extensions(&[path_to_schema_source(path)], extensions) } else { let paths = path @@ -81,7 +81,7 @@ fn build_schema_from_path(schema_file: &str) -> DiagnosticsResult { .collect(); build_schema_with_extensions(&sdls, extensions) - }; + } } fn path_to_schema_source(path: &Path) -> (String, SourceLocationKey) { diff --git a/compiler/crates/schema/Cargo.toml b/compiler/crates/schema/Cargo.toml index 04382e25864ff..201237ca0bd6a 100644 --- a/compiler/crates/schema/Cargo.toml +++ b/compiler/crates/schema/Cargo.toml @@ -19,13 +19,13 @@ flatbuffers = "2.0" fnv = "1.0" graphql-syntax = { path = "../graphql-syntax" } intern = { path = "../intern" } -lazy_static = "1.4" +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } ouroboros = "0.18.4" rayon = "1.9.0" schema-flatbuffer = { path = "../schema-flatbuffer" } serde = { version = "1.0.185", features = ["derive", "rc"] } strsim = "0.10.0" -thiserror = "1.0.64" +thiserror = "2" [dev-dependencies] fixture-tests = { path = "../fixture-tests" } diff --git a/compiler/crates/schema/src/in_memory.rs b/compiler/crates/schema/src/in_memory.rs index 94d8db2bf047f..975f35e2b4eab 100644 --- a/compiler/crates/schema/src/in_memory.rs +++ b/compiler/crates/schema/src/in_memory.rs @@ -365,6 +365,10 @@ impl InMemorySchema { self.enums.iter() } + pub fn get_enums_par_iter(&self) -> impl ParallelIterator { + self.enums.par_iter() + } + pub fn get_objects(&self) -> impl Iterator { self.objects.iter() } diff --git a/compiler/crates/schema/src/schema.rs b/compiler/crates/schema/src/schema.rs index 76186af6c7b64..89106b8274b82 100644 --- a/compiler/crates/schema/src/schema.rs +++ b/compiler/crates/schema/src/schema.rs @@ -389,6 +389,13 @@ impl SDLSchema { } } + pub fn get_enums_par_iter(&self) -> impl ParallelIterator { + match self { + SDLSchema::FlatBuffer(_schema) => todo!(), + SDLSchema::InMemory(schema) => schema.get_enums_par_iter(), + } + } + pub fn get_objects(&self) -> impl Iterator { match self { SDLSchema::FlatBuffer(_schema) => todo!(), diff --git a/compiler/crates/signedsource/Cargo.toml b/compiler/crates/signedsource/Cargo.toml index 4d68654fea935..f3adc0f337017 100644 --- a/compiler/crates/signedsource/Cargo.toml +++ b/compiler/crates/signedsource/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/facebook/relay" license = "MIT" [dependencies] -hex = "0.4.3" -lazy_static = "1.4" +hex = { version = "0.4.3", features = ["alloc"] } +lazy_static = { version = "1.5", features = ["spin_no_std"], default-features = false } md-5 = "0.10" -regex = "1.9.2" +regex = "1.11.1" diff --git a/compiler/fixture_dirs.txt b/compiler/fixture_dirs.txt index 2de33294de59c..bf77c78e8c7bb 100644 --- a/compiler/fixture_dirs.txt +++ b/compiler/fixture_dirs.txt @@ -94,6 +94,7 @@ crates/relay-transforms/tests/validate_no_unselectable_selections crates/relay-transforms/tests/validate_module_names crates/relay-transforms/tests/validate_relay_directives crates/relay-transforms/tests/validate_required_arguments +crates/relay-transforms/tests/validate_client_schema_extensions_use_catch crates/relay-transforms/tests/validate_server_only_directives crates/relay-transforms/tests/validate_static_args crates/relay-transforms/tests/validate_unused_variables diff --git a/compiler/test-project-res/src/__generated__/User_relayResolvers_graphql.res b/compiler/test-project-res/src/__generated__/User_relayResolvers_graphql.res index e6427494b9c9d..3bc1ede1655d6 100644 --- a/compiler/test-project-res/src/__generated__/User_relayResolvers_graphql.res +++ b/compiler/test-project-res/src/__generated__/User_relayResolvers_graphql.res @@ -1,8 +1,6 @@ /* @generated */ @@warning("-30") -type greetingResolver = (RescriptRelay.resolverFragmentRefs<[#TestRelayResolver]>, ) => string - type metaResolverArgs = { status: enum_OnlineStatus_input, } @@ -16,3 +14,5 @@ type fancyGreetingResolverArgs = { } type fancyGreetingResolver = (RescriptRelay.resolverFragmentRefs<[#TestRelayResolverMultiFancyGreeting]>, fancyGreetingResolverArgs) => string +type greetingResolver = (RescriptRelay.resolverFragmentRefs<[#TestRelayResolver]>, ) => string + diff --git a/flow-typed/npm/chalk_v4.x.x.js b/flow-typed/npm/chalk_v4.x.x.js index d30d76a38905c..b73753ba68a16 100644 --- a/flow-typed/npm/chalk_v4.x.x.js +++ b/flow-typed/npm/chalk_v4.x.x.js @@ -6,9 +6,11 @@ * * @flow * @format - * @oncall relay + * @oncall react_native */ +// From: https://github.com/chalk/chalk/blob/main/source/index.d.ts + declare module 'chalk' { declare type TemplateStringsArray = $ReadOnlyArray; @@ -21,7 +23,6 @@ declare module 'chalk' { }>; declare type ChalkOptions = {| - enabled?: boolean, level?: Level, |}; @@ -32,10 +33,80 @@ declare module 'chalk' { has16m: boolean, |}; + declare class Instance implements Chalk { + constructor(options?: ChalkOptions): this; + + (...text: string[]): string; + (text: TemplateStringsArray, ...placeholders: string[]): string; + Instance: typeof Instance; + level: Level; + rgb(r: number, g: number, b: number): Chalk; + hsl(h: number, s: number, l: number): Chalk; + hsv(h: number, s: number, v: number): Chalk; + hwb(h: number, w: number, b: number): Chalk; + bgHex(color: string): Chalk; + bgKeyword(color: string): Chalk; + bgRgb(r: number, g: number, b: number): Chalk; + bgHsl(h: number, s: number, l: number): Chalk; + bgHsv(h: number, s: number, v: number): Chalk; + bgHwb(h: number, w: number, b: number): Chalk; + hex(color: string): Chalk; + keyword(color: string): Chalk; + + +reset: Chalk; + +bold: Chalk; + +dim: Chalk; + +italic: Chalk; + +underline: Chalk; + +inverse: Chalk; + +hidden: Chalk; + +strikethrough: Chalk; + + +visible: Chalk; + + +black: Chalk; + +red: Chalk; + +green: Chalk; + +yellow: Chalk; + +blue: Chalk; + +magenta: Chalk; + +cyan: Chalk; + +white: Chalk; + +gray: Chalk; + +grey: Chalk; + +blackBright: Chalk; + +redBright: Chalk; + +greenBright: Chalk; + +yellowBright: Chalk; + +blueBright: Chalk; + +magentaBright: Chalk; + +cyanBright: Chalk; + +whiteBright: Chalk; + + +bgBlack: Chalk; + +bgRed: Chalk; + +bgGreen: Chalk; + +bgYellow: Chalk; + +bgBlue: Chalk; + +bgMagenta: Chalk; + +bgCyan: Chalk; + +bgWhite: Chalk; + +bgBlackBright: Chalk; + +bgRedBright: Chalk; + +bgGreenBright: Chalk; + +bgYellowBright: Chalk; + +bgBlueBright: Chalk; + +bgMagentaBright: Chalk; + +bgCyanBright: Chalk; + +bgWhiteBright: Chalk; + + supportsColor: ColorSupport; + } + declare interface Chalk { (...text: string[]): string; (text: TemplateStringsArray, ...placeholders: string[]): string; - Instance(options?: ChalkOptions): Chalk; + Instance: typeof Instance; level: Level; rgb(r: number, g: number, b: number): Chalk; hsl(h: number, s: number, l: number): Chalk; @@ -95,7 +166,7 @@ declare module 'chalk' { +bgBlueBright: Chalk; +bgMagentaBright: Chalk; +bgCyanBright: Chalk; - +bgWhiteBrigh: Chalk; + +bgWhiteBright: Chalk; supportsColor: ColorSupport; } diff --git a/flow-typed/react.js b/flow-typed/react.js deleted file mode 100644 index 90b97cacc359e..0000000000000 --- a/flow-typed/react.js +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @oncall relay - */ - -/* eslint-disable no-unused-vars */ - -'use strict'; - -// TODO: Remove after upgrading the flow version. This was added because we changed -// the types of useTransition, startTranstion, and useDeferredValue used only in test. -declare module react { - declare export var DOM: any; - declare export var PropTypes: any; - declare export var version: string; - - declare export function checkPropTypes( - propTypes: any, - values: V, - location: string, - componentName: string, - getStack: ?() => ?string, - ): void; - - declare export var createClass: $FlowFixMe; - declare export function createContext( - defaultValue: T, - calculateChangedBits: ?(a: T, b: T) => number, - ): React$Context; - declare export var createElement: React$CreateElement; - declare export var cloneElement: React$CloneElement; - declare export function createRef(): {|current: null | T|}; - - declare export function isValidElement(element: any): boolean; - - declare export var Component: typeof React$Component; - declare export var PureComponent: typeof React$PureComponent; - declare export type ComponentType<-P> = React$ComponentType

; - declare export type MixedElement = React$MixedElement; - declare export type ElementType = React$ElementType; - declare export type Element<+C> = React$Element; - declare export var Fragment: React$FragmentType; - declare export type Key = React$Key; - declare export type RefSetter<-T> = React$RefSetter; - declare export type Node = React$Node; - declare export type Context = React$Context; - declare export type Portal = React$Portal; - declare export var ConcurrentMode: ({ - children?: React$Node, - ... - }) => React$Node; // 16.7+ - declare export var StrictMode: ({children?: React$Node, ...}) => React$Node; - - declare export var Suspense: React$ComponentType<{ - children?: React$Node, - fallback?: React$Node, - ... - }>; // 16.6+ - - declare export type ElementProps = React$ElementProps; - declare export type ElementConfig = React$ElementConfig; - declare export type ElementRef = React$ElementRef; - declare export type Config = React$Config< - Props, - DefaultProps, - >; - - declare export type ChildrenArray<+T> = $ReadOnlyArray> | T; - declare export var Children: { - map( - children: ChildrenArray, - fn: (child: $NonMaybeType, index: number) => U, - thisArg?: mixed, - ): Array<$NonMaybeType>, - forEach( - children: ChildrenArray, - fn: (child: T, index: number) => mixed, - thisArg?: mixed, - ): void, - count(children: ChildrenArray): number, - only(children: ChildrenArray): $NonMaybeType, - toArray(children: ChildrenArray): Array<$NonMaybeType>, - ... - }; - - declare export function forwardRef( - render: (props: Config, ref: React$RefSetter) => React$Node, - ): component(ref: React.RefSetter, ...Config); - - declare export function memo( - component: component(ref: React.RefSetter, ...Config), - equal?: (Config, Config) => boolean, - ): component(ref: React.RefSetter, ...Config); - - declare export function lazy( - component_: () => Promise< - $ReadOnly<{ - default: component(ref: React.RefSetter, ...Config), - ... - }>, - >, - ): component(ref: React.RefSetter, ...Config); - - declare type MaybeCleanUpFn = void | (() => void); - - declare export function useContext(context: React$Context): T; - - declare export function useState( - initialState: (() => S) | S, - ): [S, ((S => S) | S) => void]; - - declare type Dispatch = (A) => void; - - declare export function useReducer( - reducer: (S, A) => S, - initialState: S, - ): [S, Dispatch]; - - declare export function useReducer( - reducer: (S, A) => S, - initialState: S, - init: void, - ): [S, Dispatch]; - - declare export function useReducer( - reducer: (S, A) => S, - initialArg: I, - init: (I) => S, - ): [S, Dispatch]; - - declare export function useRef(initialValue: T): {|current: T|}; - - declare export function useDebugValue(value: any): void; - - declare export function useEffect( - create: () => MaybeCleanUpFn, - inputs?: ?$ReadOnlyArray, - ): void; - - declare export function useLayoutEffect( - create: () => MaybeCleanUpFn, - inputs?: ?$ReadOnlyArray, - ): void; - - declare export function useCallback< - T: (...args: $ReadOnlyArray) => mixed, - >( - callback: T, - inputs: ?$ReadOnlyArray, - ): T; - - declare export function useMemo( - create: () => T, - inputs: ?$ReadOnlyArray, - ): T; - - declare export function useImperativeHandle( - ref: {current: T | null, ...} | ((inst: T | null) => mixed) | null | void, - create: () => T, - inputs: ?$ReadOnlyArray, - ): void; - - declare export function useDeferredValue(value: T): T; - - declare export function useTransition(): [boolean, (() => void) => void]; - - declare export function startTransition(() => void): void; - - declare export type Interaction = { - name: string, - timestamp: number, - ... - }; - - declare type ProfilerOnRenderFnType = ( - id: string, - phase: 'mount' | 'update', - actualDuration: number, - baseDuration: number, - startTime: number, - commitTime: number, - interactions: Set, - ) => void; - - declare export var Profiler: React$ComponentType<{| - children?: React$Node, - id: string, - onRender: ProfilerOnRenderFnType, - |}>; - - declare type TimeoutConfig = {| - timeoutMs: number, - |}; - - declare export default {| - +DOM: typeof DOM, - +PropTypes: typeof PropTypes, - +version: typeof version, - +checkPropTypes: typeof checkPropTypes, - +memo: typeof memo, - +lazy: typeof lazy, - +createClass: typeof createClass, - +createContext: typeof createContext, - +createElement: typeof createElement, - +cloneElement: typeof cloneElement, - +createRef: typeof createRef, - +forwardRef: typeof forwardRef, - +isValidElement: typeof isValidElement, - +Component: typeof Component, - +PureComponent: typeof PureComponent, - +Fragment: React$FragmentType, - +Children: typeof Children, - +ConcurrentMode: typeof ConcurrentMode, - +StrictMode: typeof StrictMode, - +Profiler: typeof Profiler, - +Suspense: typeof Suspense, - +useContext: typeof useContext, - +useState: typeof useState, - +useReducer: typeof useReducer, - +useRef: typeof useRef, - +useEffect: typeof useEffect, - +useLayoutEffect: typeof useLayoutEffect, - +useCallback: typeof useCallback, - +useMemo: typeof useMemo, - +useImperativeHandle: typeof useImperativeHandle, - +useTransition: typeof useTransition, - +useDeferredValue: typeof useDeferredValue, - +startTransition: typeof startTransition, - |}; -} diff --git a/flow-typed/shim.js.flow b/flow-typed/shim.js.flow new file mode 100644 index 0000000000000..c8b653aaf35db --- /dev/null +++ b/flow-typed/shim.js.flow @@ -0,0 +1,13 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @oncall relay + */ + +declare class Blob {} +declare class File {} +declare class HTMLElement {} diff --git a/gulpfile.js b/gulpfile.js index bee132230ce16..9ba515d816c7a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -33,12 +33,8 @@ const del = require('del'); const fs = require('fs'); const gulp = require('gulp'); const babel = require('gulp-babel'); -const header = require('gulp-header'); const rename = require('gulp-rename'); -const gulpUtil = require('gulp-util'); const path = require('path'); -const webpack = require('webpack'); -const webpackStream = require('webpack-stream'); const RELEASE_COMMIT_SHA = process.env.RELEASE_COMMIT_SHA; if (RELEASE_COMMIT_SHA && RELEASE_COMMIT_SHA.length !== 40) { @@ -52,10 +48,6 @@ const VERSION = RELEASE_COMMIT_SHA ? `0.0.0-main-${RELEASE_COMMIT_SHA.substr(0, 8)}` : process.env.npm_package_version; -const DEVELOPMENT_HEADER = `/** - * Relay v${VERSION} - */ -`; const PRODUCTION_HEADER = `/** * Relay v${VERSION} * @@ -66,39 +58,6 @@ const PRODUCTION_HEADER = `/** */ `; -const buildDist = function (filename, opts, isProduction) { - const webpackOpts = { - externals: [/^[-/a-zA-Z0-9]+$/, /^@babel\/.+$/], - target: opts.target, - output: { - filename: filename, - libraryTarget: opts.libraryTarget, - library: opts.libraryName, - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify( - isProduction ? 'production' : 'development', - ), - }), - ], - }; - if (isProduction && !opts.noMinify) { - // See more chunks configuration here: https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693 - webpackOpts.optimization = { - minimize: true, - }; - } - return webpackStream(webpackOpts, webpack, function (err, stats) { - if (err) { - throw new gulpUtil.PluginError('webpack', err); - } - if (stats.compilation.errors.length) { - throw new gulpUtil.PluginError('webpack', stats.toString()); - } - }); -}; - // Paths from package-root const PACKAGES = 'packages'; const DIST = 'dist'; @@ -119,15 +78,6 @@ const builds = [ index: 'BabelPluginRelay.js', macro: 'BabelPluginRelay.macro.js', }, - bundles: [ - { - entry: 'BabelPluginRelay.js', - output: 'babel-plugin-relay', - libraryName: 'BabelPluginRelay', - libraryTarget: 'commonjs2', - target: 'node', - }, - ], }, { package: 'react-relay', @@ -137,26 +87,6 @@ const builds = [ legacy: 'legacy.js', ReactRelayContext: 'ReactRelayContext.js', }, - bundles: [ - { - entry: 'index.js', - output: 'react-relay', - libraryName: 'ReactRelay', - libraryTarget: 'umd', - }, - { - entry: 'hooks.js', - output: 'react-relay-hooks', - libraryName: 'ReactRelayHooks', - libraryTarget: 'umd', - }, - { - entry: 'legacy.js', - output: 'react-relay-legacy', - libraryName: 'ReactRelayLegacy', - libraryTarget: 'umd', - }, - ], }, { package: 'relay-runtime', @@ -164,52 +94,18 @@ const builds = [ index: 'index.js', experimental: 'experimental.js', }, - bundles: [ - { - entry: 'index.js', - output: 'relay-runtime', - libraryName: 'RelayRuntime', - libraryTarget: 'umd', - }, - { - entry: 'experimental.js', - output: 'relay-runtime-experimental', - libraryName: 'ReactRelayExperimental', - libraryTarget: 'umd', - }, - ], }, { package: 'relay-test-utils', exports: { index: 'index.js', }, - bundles: [ - { - entry: 'index.js', - output: 'relay-test-utils', - libraryName: 'RelayTestUtils', - libraryTarget: 'commonjs2', - target: 'node', - noMinify: true, // Note: uglify can't yet handle modern JS - }, - ], }, { package: 'relay-test-utils-internal', exports: { index: 'index.js', }, - bundles: [ - { - entry: 'index.js', - output: 'relay-test-utils-internal', - libraryName: 'RelayTestUtilsInternal', - libraryTarget: 'commonjs2', - target: 'node', - noMinify: true, // Note: uglify can't yet handle modern JS - }, - ], }, ]; @@ -295,40 +191,8 @@ const exportsFiles = gulp.series( ), ); -const bundlesTasks = []; -builds.forEach(build => { - build.bundles.forEach(bundle => { - bundlesTasks.push(function bundleTask() { - return gulp - .src(path.join(DIST, build.package, 'lib', bundle.entry)) - .pipe( - buildDist(bundle.output + '.js', bundle, /* isProduction */ false), - ) - .pipe(header(DEVELOPMENT_HEADER)) - .pipe(gulp.dest(path.join(DIST, build.package))); - }); - }); -}); -const bundles = gulp.series(bundlesTasks); - -const bundlesMinTasks = []; -builds.forEach(build => { - build.bundles.forEach(bundle => { - bundlesMinTasks.push(function bundlesMinTask() { - return gulp - .src(path.join(DIST, build.package, 'lib', bundle.entry)) - .pipe( - buildDist(bundle.output + '.min.js', bundle, /* isProduction */ true), - ) - .pipe(header(PRODUCTION_HEADER)) - .pipe(gulp.dest(path.join(DIST, build.package))); - }); - }); -}); -const bundlesMin = gulp.series(bundlesMinTasks); - const clean = () => del(DIST); -const dist = gulp.series(exportsFiles, bundles, bundlesMin); +const dist = gulp.series(exportsFiles); const watch = gulp.series(dist, () => gulp.watch(INCLUDE_GLOBS, {cwd: PACKAGES}, dist), ); diff --git a/package.json b/package.json index 6fb2d8e94264a..70cacfa33ac89 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@testing-library/react": "^16.0.1", "babel-eslint": "^10.1.0", "babel-plugin-macros": "^2.0.0", - "babel-plugin-syntax-hermes-parser": "0.24.0", + "babel-plugin-syntax-hermes-parser": "0.25.1", "babel-plugin-tester": "^6.0.1", "babel-preset-fbjs": "^3.4.0", "cosmiconfig": "^5.0.5", @@ -56,33 +56,29 @@ "eslint-plugin-jsx-a11y": "6.6.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-react": "7.30.1", - "eslint-plugin-react-hooks": "4.6.0", + "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-relay": "1.8.3", "eslint-plugin-relay-internal": "link:./packages/eslint-plugin-relay-internal", "fbjs": "^3.0.2", - "flow-bin": "^0.253.0", + "flow-bin": "^0.266.1", "glob": "^7.1.1", "graphql": "15.3.0", "gulp": "4.0.2", "gulp-babel": "8.0.0", "gulp-chmod": "3.0.0", - "gulp-header": "2.0.9", "gulp-rename": "^2.0.0", - "gulp-util": "3.0.8", - "hermes-eslint": "0.24.0", + "hermes-eslint": "0.25.1", "invariant": "^2.2.4", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "nullthrows": "^1.1.1", "prettier": "2.8.8", - "prettier-plugin-hermes-parser": "0.24.0", + "prettier-plugin-hermes-parser": "0.25.1", "promise-polyfill": "6.1.0", - "react": "0.0.0-experimental-4beb1fd8-20241118", - "react-dom": "0.0.0-experimental-4beb1fd8-20241118", - "react-refresh": "0.0.0-experimental-4beb1fd8-20241118", - "react-test-renderer": "0.0.0-experimental-4beb1fd8-20241118", - "webpack": "^5.89.0", - "webpack-stream": "^7.0.0" + "react": "0.0.0-experimental-7670501b-20241124", + "react-dom": "0.0.0-experimental-7670501b-20241124", + "react-refresh": "0.0.0-experimental-7670501b-20241124", + "react-test-renderer": "0.0.0-experimental-7670501b-20241124" }, "resolutions": { "glob-watcher": "^6.0.0" diff --git a/packages/babel-plugin-relay/compileGraphQLTag.js b/packages/babel-plugin-relay/compileGraphQLTag.js index 785f2e29e6c93..c6bcde9b4b677 100644 --- a/packages/babel-plugin-relay/compileGraphQLTag.js +++ b/packages/babel-plugin-relay/compileGraphQLTag.js @@ -18,6 +18,7 @@ import type { OperationDefinitionNode, } from 'graphql'; +// $FlowFixMe[cannot-resolve-module] const crypto = require('crypto'); const {print} = require('graphql'); const { @@ -25,6 +26,7 @@ const { join: joinPath, relative: relativePath, resolve: resolvePath, + // $FlowFixMe[cannot-resolve-module] } = require('path'); const GENERATED = './__generated__/'; @@ -34,6 +36,7 @@ const GENERATED = './__generated__/'; * cross-platform compatibility. */ function posixifyPath(path: string): string { + // $FlowFixMe[cannot-resolve-name] return process.platform === 'win32' ? path.replace(/\\/g, '/') : path; } @@ -72,6 +75,7 @@ function compileGraphQLTag( const buildCommand = state.opts?.codegenCommand ?? 'relay-compiler'; // Fallback is 'true' const isDevelopment = + // $FlowFixMe[cannot-resolve-name] (process.env.BABEL_ENV || process.env.NODE_ENV) !== 'production'; return createNode(t, state, path, definition, { diff --git a/packages/babel-plugin-relay/package.json b/packages/babel-plugin-relay/package.json index 481c05c2d8172..44d2e181e08b5 100644 --- a/packages/babel-plugin-relay/package.json +++ b/packages/babel-plugin-relay/package.json @@ -24,6 +24,6 @@ "devDependencies": { "@babel/core": "^7.25.2", "prettier": "2.8.8", - "prettier-plugin-hermes-parser": "0.24.0" + "prettier-plugin-hermes-parser": "0.25.1" } } diff --git a/packages/react-relay/ReactRelayContainerUtils.js b/packages/react-relay/ReactRelayContainerUtils.js index 91513a72b9b8c..9d171a4e3c76e 100644 --- a/packages/react-relay/ReactRelayContainerUtils.js +++ b/packages/react-relay/ReactRelayContainerUtils.js @@ -11,11 +11,11 @@ 'use strict'; -function getComponentName(component: React.ComponentType): string { +function getComponentName(component: component(...empty)): string { return component.displayName || component.name || 'Component'; } -function getContainerName(Component: React.ComponentType): string { +function getContainerName(Component: component(...empty)): string { return 'Relay(' + getComponentName(Component) + ')'; } diff --git a/packages/react-relay/ReactRelayFragmentContainer.js b/packages/react-relay/ReactRelayFragmentContainer.js index 79db5b936658f..cf9706d3c3bfe 100644 --- a/packages/react-relay/ReactRelayFragmentContainer.js +++ b/packages/react-relay/ReactRelayFragmentContainer.js @@ -46,13 +46,11 @@ type ContainerState = { */ function createContainerWithFragments< Props: {...}, - TComponent: React.ComponentType, + TComponent: component(...Props), >( Component: TComponent, fragments: FragmentMap, -): React.ComponentType< - $RelayProps, RelayProp>, -> { +): component(...$RelayProps, RelayProp>) { const containerName = getContainerName(Component); return class extends React.Component { @@ -269,12 +267,12 @@ function getRelayProp(environment: IEnvironment) { */ function createContainer< Props: {...}, - Instance, - TComponent: component(ref: React.RefSetter, ...Props), + Ref, + TComponent: component(ref: Ref, ...Props), >( Component: TComponent, fragmentSpec: GeneratedNodeMap, -): component(ref: React.RefSetter, ...$RelayProps) { +): component(ref: Ref, ...$RelayProps) { // $FlowFixMe[incompatible-return] return buildReactRelayContainer( Component, diff --git a/packages/react-relay/ReactRelayPaginationContainer.js b/packages/react-relay/ReactRelayPaginationContainer.js index 8ca7e3215deef..28f50b8b7046b 100644 --- a/packages/react-relay/ReactRelayPaginationContainer.js +++ b/packages/react-relay/ReactRelayPaginationContainer.js @@ -319,14 +319,14 @@ function toObserver(observerOrCallback: ?ObserverOrCallback): Observer { function createContainerWithFragments< Props: {...}, - TComponent: React.ComponentType, + TComponent: component(...Props), >( Component: TComponent, fragments: FragmentMap, connectionConfig: ConnectionConfig, -): React.ComponentType< - $RelayProps, RelayPaginationProp>, -> { +): component( + ...$RelayProps, RelayPaginationProp> +) { const componentName = getComponentName(Component); const containerName = getContainerName(Component); @@ -937,13 +937,13 @@ function createContainerWithFragments< * `fragmentSpec` is memoized once per environment, rather than once per * instance of the container constructed/rendered. */ -function createContainer>( +function createContainer( Component: TComponent, fragmentSpec: GeneratedNodeMap, connectionConfig: ConnectionConfig, -): React.ComponentType< - $RelayProps, RelayPaginationProp>, -> { +): component( + ...$RelayProps, RelayPaginationProp> +) { // $FlowFixMe[incompatible-return] return buildReactRelayContainer( Component, diff --git a/packages/react-relay/ReactRelayRefetchContainer.js b/packages/react-relay/ReactRelayRefetchContainer.js index 4783020290fa7..bb0ddbd04cf51 100644 --- a/packages/react-relay/ReactRelayRefetchContainer.js +++ b/packages/react-relay/ReactRelayRefetchContainer.js @@ -69,14 +69,14 @@ type ContainerState = { */ function createContainerWithFragments< Props: {...}, - TComponent: React.ComponentType, + TComponent: component(...Props), >( Component: TComponent, fragments: FragmentMap, taggedNode: GraphQLTaggedNode, -): React.ComponentType< - $RelayProps, RelayRefetchProp>, -> { +): component( + ...$RelayProps, RelayRefetchProp> +) { const containerName = getContainerName(Component); return class extends React.Component { @@ -486,13 +486,13 @@ function getRelayProp( * `fragmentSpec` is memoized once per environment, rather than once per * instance of the container constructed/rendered. */ -function createContainer>( +function createContainer( Component: TComponent, fragmentSpec: GeneratedNodeMap, taggedNode: GraphQLTaggedNode, -): React.ComponentType< - $RelayProps, RelayRefetchProp>, -> { +): component( + ...$RelayProps, RelayRefetchProp> +) { // $FlowFixMe[incompatible-return] return buildReactRelayContainer( Component, diff --git a/packages/react-relay/ReactRelayTypes.js b/packages/react-relay/ReactRelayTypes.js index 615a5a68262ff..acdc24bf3b3a6 100644 --- a/packages/react-relay/ReactRelayTypes.js +++ b/packages/react-relay/ReactRelayTypes.js @@ -144,14 +144,15 @@ type MapRelayProp = [+t: T] extends [+t: {+$fragmentType: empty, ...}] ? ?$ReadOnlyArray>> : T; -export type RelayFragmentContainer = React.ComponentType< - $RelayProps, RelayProp>, ->; +export type RelayFragmentContainer = component( + ...$RelayProps, RelayProp> +); -export type RelayPaginationContainer = React.ComponentType< - $RelayProps, RelayPaginationProp>, ->; +export type RelayPaginationContainer = + component( + ...$RelayProps, RelayPaginationProp> + ); -export type RelayRefetchContainer = React.ComponentType< - $RelayProps, RelayRefetchProp>, ->; +export type RelayRefetchContainer = component( + ...$RelayProps, RelayRefetchProp> +); diff --git a/packages/react-relay/__flowtests__/ReactRelayPaginationContainer-flowtest.js b/packages/react-relay/__flowtests__/ReactRelayPaginationContainer-flowtest.js index 299c4e9e428ef..93f31f7958aeb 100644 --- a/packages/react-relay/__flowtests__/ReactRelayPaginationContainer-flowtest.js +++ b/packages/react-relay/__flowtests__/ReactRelayPaginationContainer-flowtest.js @@ -22,10 +22,7 @@ const {graphql} = require('relay-runtime'); * type-checked correctly on Relay components. */ -/* $FlowFixMe(>=0.53.0) This comment suppresses an error - * when upgrading Flow's support for React. Common errors found when upgrading - * Flow's React support are documented at https://fburl.com/eq7bs81w */ -class FooComponent extends React.Component { +class FooComponent extends React.Component<$FlowFixMe> { props: { optionalProp?: {foo: number, ...}, defaultProp: string, @@ -56,7 +53,7 @@ class FooComponent extends React.Component { } // Note that we must reassign to a new identifier to make sure flow doesn't propogate types without // the relay type definition doing the work. -const Foo = createPaginationContainer( +const Foo = createPaginationContainer<$FlowFixMe, _>( FooComponent, { viewer: graphql` diff --git a/packages/react-relay/__flowtests__/ReactRelayRefetchContainer-flowtest.js b/packages/react-relay/__flowtests__/ReactRelayRefetchContainer-flowtest.js index b39c0e40c1964..1a03fbcf862b3 100644 --- a/packages/react-relay/__flowtests__/ReactRelayRefetchContainer-flowtest.js +++ b/packages/react-relay/__flowtests__/ReactRelayRefetchContainer-flowtest.js @@ -21,10 +21,7 @@ const {graphql} = require('relay-runtime'); * Verifies that normal prop type checking works correctly on Relay components. */ -/* $FlowFixMe(>=0.53.0) This comment suppresses an error - * when upgrading Flow's support for React. Common errors found when upgrading - * Flow's React support are documented at https://fburl.com/eq7bs81w */ -class FooComponent extends React.Component { +class FooComponent extends React.Component<$FlowFixMe> { props: { optionalProp?: {foo: number, ...}, defaultProp: string, @@ -55,7 +52,7 @@ class FooComponent extends React.Component { } // Note that we must reassign to a new identifier to make sure flow doesn't propogate types without // the relay type definition doing the work. -const Foo = createRefetchContainer( +const Foo = createRefetchContainer<$FlowFixMe, _>( FooComponent, { viewer: graphql` diff --git a/packages/react-relay/__tests__/LiveResolvers-test.js b/packages/react-relay/__tests__/LiveResolvers-test.js index 48836d8b7be79..d6bce21685cac 100644 --- a/packages/react-relay/__tests__/LiveResolvers-test.js +++ b/packages/react-relay/__tests__/LiveResolvers-test.js @@ -39,6 +39,9 @@ const { } = require('relay-runtime/store/RelayModernOperationDescriptor'); const RelayModernStore = require('relay-runtime/store/RelayModernStore'); const RelayRecordSource = require('relay-runtime/store/RelayRecordSource'); +const { + RELAY_READ_TIME_RESOLVER_KEY_PREFIX, +} = require('relay-runtime/store/RelayStoreUtils'); const { disallowConsoleErrors, disallowWarnings, @@ -403,6 +406,7 @@ test('Outer resolvers do not overwrite subscriptions made by inner resolvers (re }); TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual(null); // Calling increment here should be ignored by Relay. However, if there are @@ -411,12 +415,14 @@ test('Outer resolvers do not overwrite subscriptions made by inner resolvers (re GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }); TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual(null); // Revering optimistic update puts inner back into a state where its // fragment is valid. HOWEVER, if a dangling subscription has marked inner // as dirty, we will try to read from a LiveValue that does not exist. TestRenderer.act(() => update.dispose()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('1'); // Not part of the repro, but just to confirm: We should now be resubscribed... @@ -424,6 +430,7 @@ test('Outer resolvers do not overwrite subscriptions made by inner resolvers (re GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }); TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('2'); }); @@ -496,6 +503,7 @@ test("Resolvers without fragments aren't reevaluated when their parent record up TestRenderer.act(() => jest.runAllImmediates()); expect(counterNoFragmentResolver.callCount).toBe(initialCallCount + 1); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('0'); }); @@ -561,10 +569,12 @@ test('Can suspend', () => { }); // If do not trigger `act` here, the renderer is still `0`. Probably, a React thing... TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Loading...'); TestRenderer.act(() => { GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('2'); }); @@ -633,10 +643,12 @@ test('Can suspend with resolver that uses live resolver', () => { }); // If do not trigger `act` here, the renderer is still `0`. Probably, a React thing... TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Loading...'); TestRenderer.act(() => { GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Alice 2'); TestRenderer.act(() => { const operationDescriptor = createOperationDescriptor( @@ -647,6 +659,7 @@ test('Can suspend with resolver that uses live resolver', () => { me: {id: '1', name: 'Bob', __typename: 'User'}, }); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Bob 2'); }); @@ -877,6 +890,7 @@ describe('Live Resolver with Suspense and Missing Data', () => { }); skipIf( + // $FlowFixMe[cannot-resolve-name] process.env.OSS, 'Live Resolver with Missing Data and @required', async () => { @@ -1387,7 +1401,7 @@ describe('client-only fragments', () => { const LiveResolversTestLiveResolverSuspenseQuery = graphql` query LiveResolversTestLiveResolverSuspenseQuery($id: ID!) { node(id: $id) { - ...LiveResolversTestCounterUserFragment + ...LiveResolversTestCounterUserFragment @dangerously_unaliased_fixme } } `; @@ -1444,10 +1458,12 @@ describe('client-only fragments', () => { GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }); TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Loading...'); TestRenderer.act(() => { GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('2'); }); @@ -1477,10 +1493,13 @@ describe('client-only fragments', () => { GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }); TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Loading...'); environment.applyUpdate({ storeUpdater: store => { - const record = store.get('client:1:counter_suspends_when_odd'); + const record = store.get( + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_suspends_when_odd`, + ); // this will force the invalid `liveState` value` in the resolver record record?.setValue(undefined, '__resolverLiveStateValue'); }, @@ -1488,8 +1507,9 @@ describe('client-only fragments', () => { expect(() => { GLOBAL_STORE.dispatch({type: 'INCREMENT'}); }).toThrowError( - 'Unexpected LiveState value returned from Relay Resolver internal field `RELAY_RESOLVER_LIVE_STATE_VALUE`. It is likely a bug in Relay, or a corrupt state of the relay store state Field Path `counter_suspends_when_odd`. Record `{"__id":"client:1:counter_suspends_when_odd","__typename":"__RELAY_RESOLVER__","__resolverError":null,"__resolverValue":{"__LIVE_RESOLVER_SUSPENSE_SENTINEL":true},"__resolverLiveStateDirty":true}`.', + 'Unexpected LiveState value returned from Relay Resolver internal field `RELAY_RESOLVER_LIVE_STATE_VALUE`. It is likely a bug in Relay, or a corrupt state of the relay store state Field Path `counter_suspends_when_odd`. Record `{"__id":"client:1:$r:counter_suspends_when_odd","__typename":"__RELAY_RESOLVER__","__resolverError":null,"__resolverValue":{"__LIVE_RESOLVER_SUSPENSE_SENTINEL":true},"__resolverLiveStateDirty":true}`.', ); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Loading...'); }); }); @@ -1682,7 +1702,7 @@ test('Errors when reading a @live resolver that does not return a LiveState obje }); const data = environment.lookup(operation.fragment); - expect(data.errorResponseFields).toEqual([ + expect(data.fieldErrors).toEqual([ { kind: 'relay_resolver.error', owner: 'LiveResolversTest18Query', @@ -1738,7 +1758,7 @@ test('provided variables and resolvers', () => { }); const snapshot = environment.lookup(operation.fragment); - expect(snapshot.errorResponseFields).toEqual(null); + expect(snapshot.fieldErrors).toEqual(null); expect(snapshot.data).toEqual({ hello_world_with_provided_variable: 'Hello, Hello, World!!', }); @@ -1763,7 +1783,7 @@ test('allows dependencies to be provided through the store', () => { }); const snapshot = environment.lookup(operation.fragment); - expect(snapshot.errorResponseFields).toEqual(null); + expect(snapshot.fieldErrors).toEqual(null); expect(snapshot.data).toEqual({ hello_world_with_context: 'Hello Hello Allemaal!!', }); @@ -1790,7 +1810,7 @@ test('allows objects to be provided to be provided through the store', () => { }); const snapshot = environment.lookup(operation.fragment); - expect(snapshot.errorResponseFields).toEqual(null); + expect(snapshot.fieldErrors).toEqual(null); expect(snapshot.data).toEqual({ hello_world_with_context_object: 'Hello Hello Allemaal!!', }); @@ -1876,3 +1896,156 @@ test('ResolverContext can contain observable values', async () => { counter_context: 1, }); }); + +test('ResolverContext as passed through nested resolver counters', async () => { + const source = RelayRecordSource.create({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + me: {__ref: '1'}, + }, + '1': { + __id: '1', + __typename: 'User', + id: '1', + }, + }); + const FooQuery = graphql` + query LiveResolversTestCounterContextBaseQuery { + base_counter_context { + count_plus_one + } + } + `; + + let next: (v: number) => void = () => { + throw new Error('next() not initialized'); + }; + + const operation = createOperationDescriptor(FooQuery, {}); + const store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + resolverContext: { + counter: Observable.create(observer => { + next = (value: number) => observer.next(value); + }), + }, + }); + + const environment = new RelayModernEnvironment({ + network: RelayNetwork.create(jest.fn()), + store, + }); + + let observedCounter = null; + + const snapshot = environment.lookup(operation.fragment); + // $FlowFixMe[unclear-type] - lookup() doesn't have the nice types of reading a fragment through the actual APIs: + observedCounter = (snapshot.data: any).base_counter_context.count_plus_one; + + const environmentUpdateHandler = jest.fn(() => { + const s = environment.lookup(operation.fragment); + // $FlowFixMe[unclear-type] - lookup() doesn't have the nice types of reading a fragment through the actual APIs: + observedCounter = (s.data: any).base_counter_context.count_plus_one; + }); + const disposable = environment.subscribe( + snapshot, + // $FlowFixMe[invalid-tuple-arity] Error found while enabling LTI on this file + environmentUpdateHandler, + ); + + // SETUP COMPLETE + + // Read the initial value + expect(observedCounter).toBe(0); + expect(environmentUpdateHandler).not.toHaveBeenCalled(); + + // Increment and assert we get notified of the new value + next(43); + expect(environmentUpdateHandler).toHaveBeenCalledTimes(1); + expect(observedCounter).toBe(44); + + // Unsubscribe then increment and assert don't get notified. + disposable.dispose(); + next(1); + expect(environmentUpdateHandler).toHaveBeenCalledTimes(1); + expect(observedCounter).toBe(44); + + // Explicitly read and assert we see the incremented value + // missed before due to unsubscribing. + const nextSnapshot = environment.lookup(operation.fragment); + + expect(nextSnapshot.data).toEqual({ + base_counter_context: { + count_plus_one: 2, + }, + }); +}); + +test('Defer does not prevent suspense from a deferred fragment', () => { + const source = RelayRecordSource.create({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + }, + }); + + const Fragment = graphql` + fragment LiveResolversTestDeferFragment on Query { + counter_suspends_when_odd + } + `; + const FooQuery = graphql` + query LiveResolversTestDeferQuery { + ...LiveResolversTestDeferFragment @defer + } + `; + + const store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + }); + + // Make the value odd for `counter_suspends_when_odd` + GLOBAL_STORE.dispatch({type: 'INCREMENT'}); + + const environment = new RelayModernEnvironment({ + network: RelayNetwork.create(jest.fn()), + store, + }); + environment.commitPayload( + createOperationDescriptor(getRequest(FooQuery), {}), + { + me: {id: '1'}, + }, + ); + + function Environment({children}: {children: React.Node}) { + return ( + + {children} + + ); + } + + function TestComponent() { + const queryData = useLazyLoadQuery(FooQuery, {}); + const fragmentData = useFragment(Fragment, queryData); + return fragmentData.counter_suspends_when_odd; + } + + let renderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + , + ); + }); + // @defer does not prevent suspense from a resolve field + expect(renderer?.toJSON()).toEqual('Loading...'); + TestRenderer.act(() => { + GLOBAL_STORE.dispatch({type: 'INCREMENT'}); + }); + TestRenderer.act(() => jest.runAllImmediates()); + expect(renderer?.toJSON()).toEqual('2'); +}); diff --git a/packages/react-relay/__tests__/ReactRelayFragmentContainer-WithFragmentOwnership-test.js b/packages/react-relay/__tests__/ReactRelayFragmentContainer-WithFragmentOwnership-test.js index cb30b57d7e101..19fcf5028d7ad 100644 --- a/packages/react-relay/__tests__/ReactRelayFragmentContainer-WithFragmentOwnership-test.js +++ b/packages/react-relay/__tests__/ReactRelayFragmentContainer-WithFragmentOwnership-test.js @@ -84,6 +84,7 @@ describe('ReactRelayFragmentContainer with fragment ownership', () => { ) { node(id: $id) { ...ReactRelayFragmentContainerWithFragmentOwnershipTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -94,6 +95,7 @@ describe('ReactRelayFragmentContainer with fragment ownership', () => { ) { node(id: $id) { ...ReactRelayFragmentContainerWithFragmentOwnershipTestUserFragment + @dangerously_unaliased_fixme @arguments(cond: $condGlobal) } } @@ -206,7 +208,7 @@ describe('ReactRelayFragmentContainer with fragment ownership', () => { }, __fragmentOwner: ownerUser1.request, }, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, @@ -333,7 +335,7 @@ describe('ReactRelayFragmentContainer with fragment ownership', () => { }, __fragmentOwner: ownerUser2.request, }, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, @@ -403,7 +405,7 @@ describe('ReactRelayFragmentContainer with fragment ownership', () => { }, __fragmentOwner: ownerUser1WithCondVar.request, }, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, diff --git a/packages/react-relay/__tests__/ReactRelayFragmentContainer-react-double-effects-test.js b/packages/react-relay/__tests__/ReactRelayFragmentContainer-react-double-effects-test.js index c3aa0e9bdeb11..ef7ecc9862276 100644 --- a/packages/react-relay/__tests__/ReactRelayFragmentContainer-react-double-effects-test.js +++ b/packages/react-relay/__tests__/ReactRelayFragmentContainer-react-double-effects-test.js @@ -31,7 +31,6 @@ let gqlFragment; let variables; let renderSpy; -// TODO(T83890478): enable once double invoked effects lands in xplat describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { beforeEach(() => { // Set up feature flags @@ -50,6 +49,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { ) { node(id: $id) { ...ReactRelayFragmentContainerReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -127,6 +127,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice', 'render: Alice', 'commit: Alice', 'cleanup: Alice', @@ -148,6 +149,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice Updated', 'render: Alice Updated', 'cleanup: Alice', 'commit: Alice Updated', diff --git a/packages/react-relay/__tests__/ReactRelayFragmentContainer-test.js b/packages/react-relay/__tests__/ReactRelayFragmentContainer-test.js index 40d9f3d73c6ca..d90987ba022cb 100644 --- a/packages/react-relay/__tests__/ReactRelayFragmentContainer-test.js +++ b/packages/react-relay/__tests__/ReactRelayFragmentContainer-test.js @@ -88,6 +88,7 @@ describe('ReactRelayFragmentContainer', () => { query ReactRelayFragmentContainerTestUserQuery($id: ID!) { node(id: $id) { ...ReactRelayFragmentContainerTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -99,6 +100,7 @@ describe('ReactRelayFragmentContainer', () => { ) { node(id: $id) { ...ReactRelayFragmentContainerTestUserFragment + @dangerously_unaliased_fixme @arguments(cond: $condGlobal) } } @@ -270,7 +272,7 @@ describe('ReactRelayFragmentContainer', () => { id: '4', name: 'Zuck', }, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, @@ -371,7 +373,7 @@ describe('ReactRelayFragmentContainer', () => { name: 'Joe', }, isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -429,7 +431,7 @@ describe('ReactRelayFragmentContainer', () => { // Name is excluded since value of cond is now false }, isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), diff --git a/packages/react-relay/__tests__/ReactRelayLocalQueryRenderer-test.js b/packages/react-relay/__tests__/ReactRelayLocalQueryRenderer-test.js index 50ae350bd490c..633efd050ab8b 100644 --- a/packages/react-relay/__tests__/ReactRelayLocalQueryRenderer-test.js +++ b/packages/react-relay/__tests__/ReactRelayLocalQueryRenderer-test.js @@ -44,6 +44,7 @@ describe('ReactRelayLocalQueryRenderer', () => { lastName } ...ReactRelayLocalQueryRendererTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/__tests__/ReactRelayPaginationContainer-WithFragmentOwnership-test.js b/packages/react-relay/__tests__/ReactRelayPaginationContainer-WithFragmentOwnership-test.js index 44a0dc47446e6..833acfc2bd1b2 100644 --- a/packages/react-relay/__tests__/ReactRelayPaginationContainer-WithFragmentOwnership-test.js +++ b/packages/react-relay/__tests__/ReactRelayPaginationContainer-WithFragmentOwnership-test.js @@ -115,6 +115,7 @@ describe('ReactRelayPaginationContainer with fragment ownership', () => { id __typename ...ReactRelayPaginationContainerWithFragmentOwnershipTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby) } } diff --git a/packages/react-relay/__tests__/ReactRelayPaginationContainer-react-double-effects-test.js b/packages/react-relay/__tests__/ReactRelayPaginationContainer-react-double-effects-test.js index 557952997d923..a64545cc0994b 100644 --- a/packages/react-relay/__tests__/ReactRelayPaginationContainer-react-double-effects-test.js +++ b/packages/react-relay/__tests__/ReactRelayPaginationContainer-react-double-effects-test.js @@ -31,7 +31,6 @@ let gqlFragment; let variables; let renderSpy; -// TODO(T83890478): enable once double invoked effects lands in xplat describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { beforeEach(() => { // Set up feature flags @@ -51,6 +50,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { ) { node(id: $id) { ...ReactRelayPaginationContainerReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -142,6 +142,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice', 'render: Alice', 'commit: Alice', 'cleanup: Alice', @@ -163,6 +164,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice Updated', 'render: Alice Updated', 'cleanup: Alice', 'commit: Alice Updated', diff --git a/packages/react-relay/__tests__/ReactRelayPaginationContainer-test.js b/packages/react-relay/__tests__/ReactRelayPaginationContainer-test.js index 19f60ef692c7d..2ac56b98f1667 100644 --- a/packages/react-relay/__tests__/ReactRelayPaginationContainer-test.js +++ b/packages/react-relay/__tests__/ReactRelayPaginationContainer-test.js @@ -102,6 +102,7 @@ describe('ReactRelayPaginationContainer', () => { id __typename ...ReactRelayPaginationContainerTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby) } } @@ -343,7 +344,7 @@ describe('ReactRelayPaginationContainer', () => { expect(environment.subscribe.mock.calls[0][0]).toEqual({ data: expect.any(Object), isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -456,7 +457,7 @@ describe('ReactRelayPaginationContainer', () => { expect(environment.subscribe.mock.calls[0][0]).toEqual({ data: expect.any(Object), isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -525,7 +526,7 @@ describe('ReactRelayPaginationContainer', () => { expect(environment.subscribe.mock.calls[0][0]).toEqual({ data: expect.any(Object), isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -629,7 +630,7 @@ describe('ReactRelayPaginationContainer', () => { expect(environment.subscribe.mock.calls[0][0]).toEqual({ data: expect.any(Object), isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -815,6 +816,7 @@ describe('ReactRelayPaginationContainer', () => { node(id: $id) { id ...ReactRelayPaginationContainerTestNoConnectionUserFragment + @dangerously_unaliased_fixme } } `; @@ -870,6 +872,7 @@ describe('ReactRelayPaginationContainer', () => { node(id: $id) { id ...ReactRelayPaginationContainerTestNoConnectionOnFragmentUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/__tests__/ReactRelayQueryRenderer-test.js b/packages/react-relay/__tests__/ReactRelayQueryRenderer-test.js index b3a8eb11033d1..32a24a0421fb2 100644 --- a/packages/react-relay/__tests__/ReactRelayQueryRenderer-test.js +++ b/packages/react-relay/__tests__/ReactRelayQueryRenderer-test.js @@ -93,7 +93,7 @@ describe('ReactRelayQueryRenderer', () => { query ReactRelayQueryRendererTestQuery($id: ID = "") { node(id: $id) { id - ...ReactRelayQueryRendererTestFragment + ...ReactRelayQueryRendererTestFragment @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/__tests__/ReactRelayRefetchContainer-WithFragmentOwnership-test.js b/packages/react-relay/__tests__/ReactRelayRefetchContainer-WithFragmentOwnership-test.js index e5edd26c21b6f..d9a35af97002a 100644 --- a/packages/react-relay/__tests__/ReactRelayRefetchContainer-WithFragmentOwnership-test.js +++ b/packages/react-relay/__tests__/ReactRelayRefetchContainer-WithFragmentOwnership-test.js @@ -110,6 +110,7 @@ describe('ReactRelayRefetchContainer with fragment ownership', () => { ) { node(id: $id) { ...ReactRelayRefetchContainerWithFragmentOwnershipTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/__tests__/ReactRelayRefetchContainer-react-double-effects-test.js b/packages/react-relay/__tests__/ReactRelayRefetchContainer-react-double-effects-test.js index e75b95c8fb8be..dd10e38211f7f 100644 --- a/packages/react-relay/__tests__/ReactRelayRefetchContainer-react-double-effects-test.js +++ b/packages/react-relay/__tests__/ReactRelayRefetchContainer-react-double-effects-test.js @@ -31,7 +31,6 @@ let gqlFragment; let variables; let renderSpy; -// TODO(T83890478): enable once double invoked effects lands in xplat describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { beforeEach(() => { // Set up feature flags @@ -50,6 +49,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { ) { node(id: $id) { ...ReactRelayRefetchContainerReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -127,6 +127,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice', 'render: Alice', 'commit: Alice', 'cleanup: Alice', @@ -148,6 +149,7 @@ describe.skip('ReactRelayFragmentContainer-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice Updated', 'render: Alice Updated', 'cleanup: Alice', 'commit: Alice Updated', diff --git a/packages/react-relay/__tests__/ReactRelayRefetchContainer-test.js b/packages/react-relay/__tests__/ReactRelayRefetchContainer-test.js index 56b2ceb8a3a13..4980e9bc45097 100644 --- a/packages/react-relay/__tests__/ReactRelayRefetchContainer-test.js +++ b/packages/react-relay/__tests__/ReactRelayRefetchContainer-test.js @@ -104,6 +104,7 @@ describe('ReactRelayRefetchContainer', () => { ) { node(id: $id) { ...ReactRelayRefetchContainerTestUserFragment + @dangerously_unaliased_fixme @arguments(cond: $condGlobal) } } @@ -112,6 +113,7 @@ describe('ReactRelayRefetchContainer', () => { query ReactRelayRefetchContainerTestUserQuery($id: ID!) { node(id: $id) { ...ReactRelayRefetchContainerTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -279,7 +281,7 @@ describe('ReactRelayRefetchContainer', () => { name: 'Zuck', }, isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -379,7 +381,7 @@ describe('ReactRelayRefetchContainer', () => { name: 'Joe', }, isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -438,7 +440,7 @@ describe('ReactRelayRefetchContainer', () => { // Name is excluded since value of cond is now false }, isMissingData: false, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, seenRecords: expect.any(Object), @@ -524,7 +526,7 @@ describe('ReactRelayRefetchContainer', () => { id: '4', // Name is excluded since value of cond is now false }, - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, diff --git a/packages/react-relay/__tests__/RelayClient3DModule-test.js b/packages/react-relay/__tests__/RelayClient3DModule-test.js index 737bf70b6ccf4..9ba4ae35e4767 100644 --- a/packages/react-relay/__tests__/RelayClient3DModule-test.js +++ b/packages/react-relay/__tests__/RelayClient3DModule-test.js @@ -12,6 +12,10 @@ 'use strict'; import type {LogEvent} from '../../relay-runtime/store/RelayStoreTypes'; +import type { + NormalizationRootNode, + NormalizationSplitOperation, +} from 'relay-runtime/util/NormalizationNode'; import MatchContainer from '../relay-hooks/MatchContainer'; import React from 'react'; @@ -116,13 +120,20 @@ beforeEach(() => { describe('ClientUser', () => { let store; let environment; + let operationLoader; beforeEach(() => { + operationLoader = { + load: jest.fn<[mixed], Promise>(), + get: jest.fn<[mixed], ?NormalizationRootNode>(), + }; store = new RelayModernStore(RelayRecordSource.create(), { log: logFn, + operationLoader, }); environment = new RelayModernEnvironment({ network: RelayNetwork.create(jest.fn()), + operationLoader, store, log: logFn, }); @@ -154,7 +165,6 @@ describe('ClientUser', () => { ); //$FlowFixMe const fragmentSnapshot = environment.lookup(fragmentSelector); - const dataSelector = getSelector( CLIENT_USER_FRAGMENT, fragmentSnapshot.data?.basicUser, @@ -185,13 +195,20 @@ describe('ClientUser', () => { describe('SpecialUser', () => { let environment; let store; + let operationLoader; beforeEach(() => { + operationLoader = { + load: jest.fn<[mixed], Promise>(), + get: jest.fn<[mixed], ?NormalizationRootNode>(), + }; store = new RelayModernStore(RelayRecordSource.create(), { log: logFn, + operationLoader, }); environment = new RelayModernEnvironment({ network: RelayNetwork.create(jest.fn()), store, + operationLoader, log: logFn, }); const operation = createOperationDescriptor(CLIENT_3D_TEST_QUERY, {}); @@ -200,6 +217,7 @@ describe('SpecialUser', () => { basicUser: { __typename: 'SpecialUser', id: '2', + data: 'specialUserData', }, }, }); @@ -221,7 +239,6 @@ describe('SpecialUser', () => { ); //$FlowFixMe const fragmentSnapshot = environment.lookup(fragmentSelector); - const dataSelector = getSelector( SPECIAL_USER_FRAGMENT, fragmentSnapshot.data?.basicUser, diff --git a/packages/react-relay/__tests__/RelayResolverModel-test.js b/packages/react-relay/__tests__/RelayResolverModel-test.js index 32ded40d0c9b6..ff937eb471291 100644 --- a/packages/react-relay/__tests__/RelayResolverModel-test.js +++ b/packages/react-relay/__tests__/RelayResolverModel-test.js @@ -282,6 +282,7 @@ describe.each([['New', useFragment]])( completeTodo('todo-1'); jest.runAllImmediates(); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Test todo - green'); }); @@ -328,6 +329,7 @@ describe.each([['New', useFragment]])( }); expect(LiveColorSubscriptions.activeSubscriptions.length).toBe(1); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Test todo - green'); TestRenderer.act(() => { @@ -335,6 +337,7 @@ describe.each([['New', useFragment]])( jest.runAllImmediates(); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual(null); // Run GC to will remove "orphan" records and unsubscribe if they have live resolver subscriptions store.scheduleGC(); @@ -378,6 +381,7 @@ describe.each([['New', useFragment]])( changeDescription('todo-1', 'Changed todo description text'); jest.runAllImmediates(); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('[x] Changed todo description text'); }); @@ -671,6 +675,7 @@ describe.each([['New', useFragment]])( setIsHuman(false); jest.runAllImmediates(); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('robot:0'); TestRenderer.act(() => { @@ -678,6 +683,7 @@ describe.each([['New', useFragment]])( setIsHuman(true); jest.runAllImmediates(); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('human:0'); TestRenderer.act(() => { diff --git a/packages/react-relay/__tests__/RelayResolverModelWithContext-test.js b/packages/react-relay/__tests__/RelayResolverModelWithContext-test.js new file mode 100644 index 0000000000000..a76c2768bf067 --- /dev/null +++ b/packages/react-relay/__tests__/RelayResolverModelWithContext-test.js @@ -0,0 +1,134 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall relay + */ + +'use strict'; + +import type {RelayResolverModelWithContextTestFragment$key} from './__generated__/RelayResolverModelWithContextTestFragment.graphql'; +import type {TestResolverContextType} from 'relay-runtime/mutations/__tests__/TestResolverContextType'; + +const React = require('react'); +const { + RelayEnvironmentProvider, + useClientQuery, + useFragment, +} = require('react-relay'); +const TestRenderer = require('react-test-renderer'); +const {Observable} = require('relay-runtime'); +const RelayNetwork = require('relay-runtime/network/RelayNetwork'); +const {graphql} = require('relay-runtime/query/GraphQLTag'); +const { + addTodo, + resetStore, +} = require('relay-runtime/store/__tests__/resolvers/ExampleTodoStore'); +const RelayModernEnvironment = require('relay-runtime/store/RelayModernEnvironment'); +const RelayModernStore = require('relay-runtime/store/RelayModernStore.js'); +const RelayRecordSource = require('relay-runtime/store/RelayRecordSource'); +const { + disallowConsoleErrors, + disallowWarnings, + injectPromisePolyfill__DEPRECATED, +} = require('relay-test-utils-internal'); + +injectPromisePolyfill__DEPRECATED(); +disallowWarnings(); +disallowConsoleErrors(); + +beforeEach(() => { + resetStore(() => {}); +}); + +function EnvironmentWrapper({ + children, + environment, +}: { + children: React.Node, + environment: RelayModernEnvironment, +}) { + return ( + + {children} + + ); +} + +const RelayResolverModelWithContextTestFragment = graphql` + fragment RelayResolverModelWithContextTestFragment on TodoModel { + id + description + another_value_from_context + } +`; + +const RelayResolverModelWithContextTestQuery = graphql` + query RelayResolverModelWithContextTestQuery($id: ID!) { + todo_model(todoID: $id) { + ...RelayResolverModelWithContextTestFragment + } + } +`; + +describe('RelayResolverModelWithContext', () => { + function TodoComponent(props: { + fragmentKey: ?RelayResolverModelWithContextTestFragment$key, + }) { + const data = useFragment( + RelayResolverModelWithContextTestFragment, + props.fragmentKey, + ); + if (data == null) { + return null; + } + + return data.another_value_from_context; + } + + function TodoRootComponent(props: {todoID: string}) { + const data = useClientQuery(RelayResolverModelWithContextTestQuery, { + id: props.todoID, + }); + if (data?.todo_model == null) { + return null; + } + + return ; + } + + test('returns a value from context when resolverDataInjector is used', () => { + const resolverContext: TestResolverContextType = { + greeting: { + myHello: 'This is a value from context', + }, + counter: Observable.create(observer => { + observer.next(10); + }), + }; + + const store = new RelayModernStore(RelayRecordSource.create(), { + resolverContext, + }); + const environment = new RelayModernEnvironment({ + network: RelayNetwork.create(jest.fn()), + store, + }); + + addTodo('Test todo'); + + let renderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + , + ); + }); + expect(renderer?.toJSON()).toEqual('This is a value from context'); + }); +}); diff --git a/packages/react-relay/__tests__/RelayResolverNullableModelClientEdge-test.js b/packages/react-relay/__tests__/RelayResolverNullableModelClientEdge-test.js index 294e3e96c534a..5fc665c05750c 100644 --- a/packages/react-relay/__tests__/RelayResolverNullableModelClientEdge-test.js +++ b/packages/react-relay/__tests__/RelayResolverNullableModelClientEdge-test.js @@ -493,7 +493,7 @@ test('Errors thrown when reading the model a client edge points to are caught as {}, ); const snapshot = environment.lookup(operation.fragment); - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { error: Error(ERROR_MESSAGE), owner: 'RelayResolverNullableModelClientEdgeTest_ErrorModel_Query', @@ -519,7 +519,7 @@ test('Errors thrown when reading plural client edge are caught as resolver error {}, ); const snapshot = environment.lookup(operation.fragment); - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { error: Error(ERROR_MESSAGE), owner: 'RelayResolverNullableModelClientEdgeTest_PluralErrorModel_Query', @@ -553,7 +553,7 @@ test('Errors thrown when reading plural client edge are caught as resolver error {}, ); const snapshot = environment.lookup(operation.fragment); - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { error: Error(ERROR_MESSAGE), owner: diff --git a/packages/react-relay/__tests__/RelayResolvers-withOutputType-test.js b/packages/react-relay/__tests__/RelayResolvers-withOutputType-test.js index 55ac740a64278..4ce49ad5577af 100644 --- a/packages/react-relay/__tests__/RelayResolvers-withOutputType-test.js +++ b/packages/react-relay/__tests__/RelayResolvers-withOutputType-test.js @@ -33,6 +33,9 @@ const { const RelayModernEnvironment = require('relay-runtime/store/RelayModernEnvironment'); const RelayModernStore = require('relay-runtime/store/RelayModernStore.js'); const RelayRecordSource = require('relay-runtime/store/RelayRecordSource'); +const { + RELAY_READ_TIME_RESOLVER_KEY_PREFIX, +} = require('relay-runtime/store/RelayStoreUtils'); const { disallowConsoleErrors, disallowWarnings, @@ -562,12 +565,14 @@ test('renders after GC', () => { 'client:root': { __id: 'client:root', __typename: '__Root', - 'todos(first:10)': { - __ref: 'client:root:todos(first:10)', + // $FlowFixMe[invalid-computed-prop] + [`${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`]: { + __ref: `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`, }, }, - 'client:root:todos(first:10)': { - __id: 'client:root:todos(first:10)', + // $FlowFixMe[invalid-computed-prop] + [`client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`]: { + __id: `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`, __resolverError: null, __resolverLiveStateDirty: false, __resolverLiveStateSubscription: expect.anything(), @@ -576,59 +581,69 @@ test('renders after GC', () => { subscribe: expect.anything(), }, __resolverOutputTypeRecordIDs: new Set([ - 'client:TodoConnection:client:root:todos(first:10)', - 'client:TodoConnection:client:root:todos(first:10):edges:0', - 'client:TodoConnection:client:root:todos(first:10):edges:0:node', - 'client:TodoConnection:client:root:todos(first:10):pageInfo', + `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`, + `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0`, + `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0:node`, + `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):pageInfo`, ]), __resolverSnapshot: undefined, - __resolverValue: 'client:TodoConnection:client:root:todos(first:10)', + __resolverValue: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`, __typename: '__RELAY_RESOLVER__', }, - 'client:TodoConnection:client:root:todos(first:10)': { - __id: 'client:TodoConnection:client:root:todos(first:10)', - __typename: 'TodoConnection', - count: 1, - edges: { - __refs: ['client:TodoConnection:client:root:todos(first:10):edges:0'], - }, - pageInfo: { - __ref: 'client:TodoConnection:client:root:todos(first:10):pageInfo', + // $FlowFixMe[invalid-computed-prop] + [`client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`]: + { + __id: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10)`, + __typename: 'TodoConnection', + count: 1, + edges: { + __refs: [ + `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0`, + ], + }, + pageInfo: { + __ref: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):pageInfo`, + }, }, - }, - 'client:TodoConnection:client:root:todos(first:10):edges:0': { - __id: 'client:TodoConnection:client:root:todos(first:10):edges:0', - __typename: 'TodoEdge', - cursor: null, - node: { - __ref: 'client:TodoConnection:client:root:todos(first:10):edges:0:node', + // $FlowFixMe[invalid-computed-prop] + [`client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0`]: + { + __id: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0`, + __typename: 'TodoEdge', + cursor: null, + node: { + __ref: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0:node`, + }, }, - }, - 'client:TodoConnection:client:root:todos(first:10):edges:0:node': { - __id: 'client:TodoConnection:client:root:todos(first:10):edges:0:node', - __typename: 'Todo', - complete: { - __ref: - 'client:TodoConnection:client:root:todos(first:10):edges:0:node:complete', + // $FlowFixMe[invalid-computed-prop] + [`client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0:node`]: + { + __id: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0:node`, + __typename: 'Todo', + // $FlowFixMe[invalid-computed-prop] + [`${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}complete`]: { + __ref: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0:node:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}complete`, + }, + // $FlowFixMe[invalid-computed-prop] + [`${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`]: { + __ref: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0:node:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + }, + // $FlowFixMe[invalid-computed-prop] + [`${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}text`]: { + __ref: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):edges:0:node:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}text`, + }, + todo_id: 'todo-1', }, - self: { - __ref: - 'client:TodoConnection:client:root:todos(first:10):edges:0:node:self', + // $FlowFixMe[invalid-computed-prop] + [`client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):pageInfo`]: + { + __id: `client:TodoConnection:client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}todos(first:10):pageInfo`, + __typename: 'TodoConnectionPageInfo', + endCursor: null, + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, }, - text: { - __ref: - 'client:TodoConnection:client:root:todos(first:10):edges:0:node:text', - }, - todo_id: 'todo-1', - }, - 'client:TodoConnection:client:root:todos(first:10):pageInfo': { - __id: 'client:TodoConnection:client:root:todos(first:10):pageInfo', - __typename: 'TodoConnectionPageInfo', - endCursor: null, - hasNextPage: false, - hasPreviousPage: false, - startCursor: null, - }, }); expect(() => { diff --git a/packages/react-relay/__tests__/__generated__/LiveResolversTestCounterContextBaseQuery.graphql.js b/packages/react-relay/__tests__/__generated__/LiveResolversTestCounterContextBaseQuery.graphql.js new file mode 100644 index 0000000000000..5d4b8c17d45d2 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/LiveResolversTestCounterContextBaseQuery.graphql.js @@ -0,0 +1,176 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<743370490ceef61e2730285c6cb8f8cf>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ClientRequest, ClientQuery } from 'relay-runtime'; +import type { LiveState } from "relay-runtime"; +import type { BaseCounter____relay_model_instance$data } from "./../../../relay-runtime/store/__tests__/resolvers/__generated__/BaseCounter____relay_model_instance.graphql"; +import {count_plus_one as baseCounterCountPlusOneResolverType} from "../../../relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver.js"; +import type { TestResolverContextType } from "../../../relay-runtime/mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `baseCounterCountPlusOneResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(baseCounterCountPlusOneResolverType: ( + __relay_model_instance: BaseCounter____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => LiveState); +import {base_counter_context as queryBaseCounterContextResolverType} from "../../../relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver.js"; +// Type assertion validating that `queryBaseCounterContextResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryBaseCounterContextResolverType: ( + args: void, + context: TestResolverContextType, +) => LiveState); +import type { BaseCounter } from "../../../relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver.js"; +export type LiveResolversTestCounterContextBaseQuery$variables = {||}; +export type LiveResolversTestCounterContextBaseQuery$data = {| + +base_counter_context: ?{| + +count_plus_one: ?number, + |}, +|}; +export type LiveResolversTestCounterContextBaseQuery = {| + response: LiveResolversTestCounterContextBaseQuery$data, + variables: LiveResolversTestCounterContextBaseQuery$variables, +|}; +*/ + +var node/*: ClientRequest*/ = { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "LiveResolversTestCounterContextBaseQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "concreteType": "BaseCounter", + "modelResolvers": null, + "backingField": { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayLiveResolver", + "name": "base_counter_context", + "resolverModule": require('./../../../relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver').base_counter_context, + "path": "base_counter_context", + "normalizationInfo": { + "kind": "WeakModel", + "concreteType": "BaseCounter", + "plural": false + } + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "BaseCounter", + "kind": "LinkedField", + "name": "base_counter_context", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "BaseCounter____relay_model_instance" + }, + "kind": "RelayLiveResolver", + "name": "count_plus_one", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./../../../relay-runtime/store/__tests__/resolvers/__generated__/BaseCounter____relay_model_instance.graphql'), require('./../../../relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver').count_plus_one, '__relay_model_instance', true), + "path": "base_counter_context.count_plus_one" + } + ], + "storageKey": null + } + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "LiveResolversTestCounterContextBaseQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "backingField": { + "name": "base_counter_context", + "args": null, + "fragment": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "BaseCounter", + "kind": "LinkedField", + "name": "base_counter_context", + "plural": false, + "selections": [ + { + "name": "count_plus_one", + "args": null, + "fragment": { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__relay_model_instance", + "storageKey": null + } + ], + "type": "BaseCounter", + "abstractKey": null + }, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + } + ], + "storageKey": null + } + } + ] + }, + "params": { + "cacheID": "97f0edeb9700f58debe76b3ab0ca4f82", + "id": null, + "metadata": {}, + "name": "LiveResolversTestCounterContextBaseQuery", + "operationKind": "query", + "text": null + } +}; + +if (__DEV__) { + (node/*: any*/).hash = "a7ba71ed7b3caaefa42c8686bc81819c"; +} + +module.exports = ((node/*: any*/)/*: ClientQuery< + LiveResolversTestCounterContextBaseQuery$variables, + LiveResolversTestCounterContextBaseQuery$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/LiveResolversTestDeferFragment.graphql.js b/packages/react-relay/__tests__/__generated__/LiveResolversTestDeferFragment.graphql.js new file mode 100644 index 0000000000000..07850c7cf18f2 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/LiveResolversTestDeferFragment.graphql.js @@ -0,0 +1,75 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { CounterSuspendsWhenOdd$key } from "./../../../relay-runtime/store/__tests__/resolvers/__generated__/CounterSuspendsWhenOdd.graphql"; +import type { LiveState, FragmentType } from "relay-runtime"; +import {counter_suspends_when_odd as queryCounterSuspendsWhenOddResolverType} from "../../../relay-runtime/store/__tests__/resolvers/CounterSuspendsWhenOdd.js"; +import type { TestResolverContextType } from "../../../relay-runtime/mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `queryCounterSuspendsWhenOddResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryCounterSuspendsWhenOddResolverType: ( + rootKey: CounterSuspendsWhenOdd$key, + args: void, + context: TestResolverContextType, +) => LiveState); +declare export opaque type LiveResolversTestDeferFragment$fragmentType: FragmentType; +export type LiveResolversTestDeferFragment$data = {| + +counter_suspends_when_odd: ?number, + +$fragmentType: LiveResolversTestDeferFragment$fragmentType, +|}; +export type LiveResolversTestDeferFragment$key = { + +$data?: LiveResolversTestDeferFragment$data, + +$fragmentSpreads: LiveResolversTestDeferFragment$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "LiveResolversTestDeferFragment", + "selections": [ + { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "CounterSuspendsWhenOdd" + }, + "kind": "RelayLiveResolver", + "name": "counter_suspends_when_odd", + "resolverModule": require('./../../../relay-runtime/store/__tests__/resolvers/CounterSuspendsWhenOdd').counter_suspends_when_odd, + "path": "counter_suspends_when_odd" + } + ], + "type": "Query", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "b0021654a94dd7cd7005caf576f7ba36"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + LiveResolversTestDeferFragment$fragmentType, + LiveResolversTestDeferFragment$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/LiveResolversTestDeferQuery.graphql.js b/packages/react-relay/__tests__/__generated__/LiveResolversTestDeferQuery.graphql.js new file mode 100644 index 0000000000000..c54c94bc834fd --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/LiveResolversTestDeferQuery.graphql.js @@ -0,0 +1,129 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<87df34e52623f9638b06152e37b9591c>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { LiveResolversTestDeferFragment$fragmentType } from "./LiveResolversTestDeferFragment.graphql"; +export type LiveResolversTestDeferQuery$variables = {||}; +export type LiveResolversTestDeferQuery$data = {| + +$fragmentSpreads: LiveResolversTestDeferFragment$fragmentType, +|}; +export type LiveResolversTestDeferQuery = {| + response: LiveResolversTestDeferQuery$data, + variables: LiveResolversTestDeferQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "LiveResolversTestDeferQuery", + "selections": [ + { + "kind": "Defer", + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "LiveResolversTestDeferFragment" + } + ] + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "LiveResolversTestDeferQuery", + "selections": [ + { + "if": null, + "kind": "Defer", + "label": "LiveResolversTestDeferQuery$defer$LiveResolversTestDeferFragment", + "selections": [ + { + "name": "counter_suspends_when_odd", + "args": null, + "fragment": { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + } + ] + } + ] + }, + "params": { + "cacheID": "3d21f7198375d03268b15f6dd226cffd", + "id": null, + "metadata": {}, + "name": "LiveResolversTestDeferQuery", + "operationKind": "query", + "text": "query LiveResolversTestDeferQuery {\n ...LiveResolversTestDeferFragment @defer(label: \"LiveResolversTestDeferQuery$defer$LiveResolversTestDeferFragment\")\n}\n\nfragment CounterSuspendsWhenOdd on Query {\n me {\n id\n }\n}\n\nfragment LiveResolversTestDeferFragment on Query {\n ...CounterSuspendsWhenOdd\n}\n" + } +}; + +if (__DEV__) { + (node/*: any*/).hash = "ae82e55c303b6b124964901fdf647b8a"; +} + +module.exports = ((node/*: any*/)/*: Query< + LiveResolversTestDeferQuery$variables, + LiveResolversTestDeferQuery$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/LiveResolversTestLiveResolverSuspenseQuery.graphql.js b/packages/react-relay/__tests__/__generated__/LiveResolversTestLiveResolverSuspenseQuery.graphql.js index effbd0722a5a9..9fc8c9646fe6e 100644 --- a/packages/react-relay/__tests__/__generated__/LiveResolversTestLiveResolverSuspenseQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/LiveResolversTestLiveResolverSuspenseQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9c526503810e8356431d34d4bb60779a>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -140,7 +140,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "068b94edeee505324b2540cd3f157307"; + (node/*: any*/).hash = "d8986066eeaf1dab3efb1495e3820b43"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerReactDoubleEffectsTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerReactDoubleEffectsTestUserQuery.graphql.js index 8ea18f92ca076..48a94a2e13f62 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerReactDoubleEffectsTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerReactDoubleEffectsTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<69d8411257601e1142fecb6b2c50b44a>> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "b3bff2e0a46eaf7e4382f6fbf75d02ac"; + (node/*: any*/).hash = "2267a7b5958025ee93de3427d77a90ac"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserQuery.graphql.js index a5fc17334a515..f5fa41a2bb191 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<5d3dadb543af02911aa402ccea0c3da4>> + * @generated SignedSource<<9088238905a709c5e8e410a00f06fb63>> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "0e22a390b8b36d761b73909bcdbaf606"; + (node/*: any*/).hash = "77aa337a1abdd22ab4e7d85da3ffc8c6"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserWithCondQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserWithCondQuery.graphql.js index b5b1f12241e0b..b6a538bde191f 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserWithCondQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerTestUserWithCondQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6b2101bac612118a648c66c84db7de1e>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -157,7 +157,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "810e07ba9d2d6d4dd6194dd3f49b1211"; + (node/*: any*/).hash = "236716637f5e84cb62c420776a4d9838"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestUserQuery.graphql.js index bcfd152098240..4f7880545f0dd 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<32a25b5f1bc39fd59c49d7e54abd07e1>> + * @generated SignedSource<<9b5834e69eb9329b872f158917a0fd48>> * @flow * @lightSyntaxTransform * @nogrep @@ -141,7 +141,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "20539d35a38e31c9ccbdd6b4d54aec21"; + (node/*: any*/).hash = "93b6d7b88ae03eb88e1eb60be7cb244d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestWithCondUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestWithCondUserQuery.graphql.js index 4db44be34036f..f8e62a3de2553 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestWithCondUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayFragmentContainerWithFragmentOwnershipTestWithCondUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<98c104eef25d992b6fce2fad458e9b79>> + * @generated SignedSource<<885d6675bd00f1ad0bbefc43c0f7595d>> * @flow * @lightSyntaxTransform * @nogrep @@ -164,7 +164,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "577a07568a7abf3e31c0e6f44fb64a8d"; + (node/*: any*/).hash = "02786543a0348beed6020ab497c904e6"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayLocalQueryRendererTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayLocalQueryRendererTestUserQuery.graphql.js index 768134c186a02..a01ab54e91e02 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayLocalQueryRendererTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayLocalQueryRendererTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<96724d396fb1effe971de29910a1d9f4>> + * @generated SignedSource<<13dfe6bf725d6392e60940fad4056ebe>> * @flow * @lightSyntaxTransform * @nogrep @@ -154,7 +154,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f46ad8fa64eb4b5933ed039b4cc94e16"; + (node/*: any*/).hash = "24c704b361b5a05121618dff23ef81f9"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerReactDoubleEffectsTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerReactDoubleEffectsTestUserQuery.graphql.js index 59dd9badc7e74..a2ec729c43b92 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerReactDoubleEffectsTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerReactDoubleEffectsTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -231,7 +231,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "9abbd5101c0d2ac96fcf72a41c26a948"; + (node/*: any*/).hash = "1115325f54d6d9cdc55d128aa5647048"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionOnFragmentUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionOnFragmentUserQuery.graphql.js index 13c9bc9349118..f78e9ca534d55 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionOnFragmentUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionOnFragmentUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<291f86500cd237cbb5e4f56c15d52e78>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -288,7 +288,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "16cf027e832c7432065f4965429431c0"; + (node/*: any*/).hash = "66bbe4963a808c62bf186f33395775b7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionUserQuery.graphql.js index 7901f02d3e95e..d8fafecf02d46 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestNoConnectionUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<05b2793371ff21dc1a2523949eaedeeb>> * @flow * @lightSyntaxTransform * @nogrep @@ -223,7 +223,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "87f6a6ca60ee4bf34ab055283ec5b341"; + (node/*: any*/).hash = "0c78e21bfeadc7de224add3a607c917f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestUserQuery.graphql.js index 8766c7bc38535..5ddfd631ad6b1 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<40317e714e5cb9a352d44ac9057da374>> + * @generated SignedSource<<1d4e247dea3b7195e03e16e4673cf51c>> * @flow * @lightSyntaxTransform * @nogrep @@ -276,7 +276,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "50a3bd82c5fad5ead1ce004df8427725"; + (node/*: any*/).hash = "f780c50ab163e4a29c81eb497cfd5d1b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerWithFragmentOwnershipTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerWithFragmentOwnershipTestUserQuery.graphql.js index be3f0f3e3b5fb..7fc7398bf4959 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerWithFragmentOwnershipTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayPaginationContainerWithFragmentOwnershipTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<949c292c388e628caec8bca19f66fbef>> + * @generated SignedSource<<830ef30aafdb7a89e6f86de3cb2142fa>> * @flow * @lightSyntaxTransform * @nogrep @@ -290,7 +290,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "46153f91be065033bb3e83f093819f1b"; + (node/*: any*/).hash = "e9d0c6d0cb6439a0d13db8521b4cefe3"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayQueryRendererTestQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayQueryRendererTestQuery.graphql.js index 3d1ee97ed94d4..3b1d27ade0546 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayQueryRendererTestQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayQueryRendererTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<8cc908af3948ba35bc9a4a3d9b018b0b>> + * @generated SignedSource<<640d3b690af15282d859679fdde281e6>> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "868a762b987be24c755ff000a86baacc"; + (node/*: any*/).hash = "9fa9b4608e79feda0a43038cfc0fa816"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerReactDoubleEffectsTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerReactDoubleEffectsTestUserQuery.graphql.js index c8ce092bbc1ab..b851faab1aba2 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerReactDoubleEffectsTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerReactDoubleEffectsTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<59211d841db5434330d8141df7099a3f>> + * @generated SignedSource<<487ca659e859dc2f0d25c7c10580f904>> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "672ea26a52c353b070b2114ac3dedb53"; + (node/*: any*/).hash = "88ddbf011c327ab1ad2e4ff9ab9012e7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserQuery.graphql.js index 3ee49392e7386..7bd3938b9fe05 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<738b3c6ab445a73362b4634006c5e06c>> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "699fa1e4a00f325e18b50aa63eb635f6"; + (node/*: any*/).hash = "d6a4a7c84fa97970ee4f08e7b3a643b2"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserWithCondQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserWithCondQuery.graphql.js index 032b407d23105..4ea6c68a91137 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserWithCondQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerTestUserWithCondQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9f0b885da902476df0579ea146e3d384>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -157,7 +157,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "ec592599ed4721431b9724f76eb81196"; + (node/*: any*/).hash = "5ead741f93728a15b610b870e2b420f2"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerWithFragmentOwnershipTestUserQuery.graphql.js b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerWithFragmentOwnershipTestUserQuery.graphql.js index 3b735b515d671..d87841ab6ebee 100644 --- a/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerWithFragmentOwnershipTestUserQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/ReactRelayRefetchContainerWithFragmentOwnershipTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<2a9062913803b91bb4a0fcb64285cc36>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "226c6570b64b74227f1cd9b069e9815e"; + (node/*: any*/).hash = "ae463ee1fb5c82b6a7b4574ac78a78ef"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/__tests__/__generated__/RelayClient3DModuleTestQuery.graphql.js b/packages/react-relay/__tests__/__generated__/RelayClient3DModuleTestQuery.graphql.js index d645fdfbf47d5..e7ca0f3eedfeb 100644 --- a/packages/react-relay/__tests__/__generated__/RelayClient3DModuleTestQuery.graphql.js +++ b/packages/react-relay/__tests__/__generated__/RelayClient3DModuleTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<1a9a6616628a9eabcb1d1df9c1fac6a3>> + * @generated SignedSource<<278cea064e359a15e34e1dc5b2c4d583>> * @flow * @lightSyntaxTransform * @nogrep @@ -105,13 +105,33 @@ return { }, { "kind": "InlineFragment", - "selections": [], + "selections": [ + { + "args": null, + "documentName": "RelayClient3DModuleTestFragment2BasicUser", + "fragmentName": "RelayClient3DModuleTestFragmentClientUser_data", + "fragmentPropName": "data", + "kind": "ModuleImport", + "componentModuleProvider": () => require('./../ClientUser.react'), + "operationModuleProvider": () => require('react-relay/__tests__/__generated__/./RelayClient3DModuleTestFragmentClientUser_data$normalization.graphql') + } + ], "type": "ClientUser", "abstractKey": null }, { "kind": "InlineFragment", - "selections": [], + "selections": [ + { + "args": null, + "documentName": "RelayClient3DModuleTestFragment2BasicUser", + "fragmentName": "RelayClient3DModuleTestFragmentSpecialUser_data", + "fragmentPropName": "data", + "kind": "ModuleImport", + "componentModuleProvider": () => require('./../SpecialUser.react'), + "operationModuleProvider": () => require('react-relay/__tests__/__generated__/./RelayClient3DModuleTestFragmentSpecialUser_data$normalization.graphql') + } + ], "type": "SpecialUser", "abstractKey": null }, diff --git a/packages/react-relay/__tests__/__generated__/RelayResolverModelWithContextTestFragment.graphql.js b/packages/react-relay/__tests__/__generated__/RelayResolverModelWithContextTestFragment.graphql.js new file mode 100644 index 0000000000000..dcb25e21bd9b1 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/RelayResolverModelWithContextTestFragment.graphql.js @@ -0,0 +1,109 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { TodoModel____relay_model_instance$data } from "./../../../relay-runtime/store/__tests__/resolvers/__generated__/TodoModel____relay_model_instance.graphql"; +import type { FragmentType } from "relay-runtime"; +import {another_value_from_context as todoModelAnotherValueFromContextResolverType} from "../../../relay-runtime/store/__tests__/resolvers/TodoModel.js"; +import type { TestResolverContextType } from "../../../relay-runtime/mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `todoModelAnotherValueFromContextResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(todoModelAnotherValueFromContextResolverType: ( + __relay_model_instance: TodoModel____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?string); +import {description as todoModelDescriptionResolverType} from "../../../relay-runtime/store/__tests__/resolvers/TodoModel.js"; +// Type assertion validating that `todoModelDescriptionResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(todoModelDescriptionResolverType: ( + __relay_model_instance: TodoModel____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?string); +declare export opaque type RelayResolverModelWithContextTestFragment$fragmentType: FragmentType; +export type RelayResolverModelWithContextTestFragment$data = {| + +another_value_from_context: ?string, + +description: ?string, + +id: string, + +$fragmentType: RelayResolverModelWithContextTestFragment$fragmentType, +|}; +export type RelayResolverModelWithContextTestFragment$key = { + +$data?: RelayResolverModelWithContextTestFragment$data, + +$fragmentSpreads: RelayResolverModelWithContextTestFragment$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = (function(){ +var v0 = { + "args": null, + "kind": "FragmentSpread", + "name": "TodoModel____relay_model_instance" +}; +return { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "RelayResolverModelWithContextTestFragment", + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "description", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./../../../relay-runtime/store/__tests__/resolvers/__generated__/TodoModel____relay_model_instance.graphql'), require('./../../../relay-runtime/store/__tests__/resolvers/TodoModel').description, '__relay_model_instance', true), + "path": "description" + }, + { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "another_value_from_context", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./../../../relay-runtime/store/__tests__/resolvers/__generated__/TodoModel____relay_model_instance.graphql'), require('./../../../relay-runtime/store/__tests__/resolvers/TodoModel').another_value_from_context, '__relay_model_instance', true), + "path": "another_value_from_context" + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ] + } + ], + "type": "TodoModel", + "abstractKey": null +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "5373c916bad7d7b7c83e32558cfde3d4"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + RelayResolverModelWithContextTestFragment$fragmentType, + RelayResolverModelWithContextTestFragment$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/RelayResolverModelWithContextTestQuery.graphql.js b/packages/react-relay/__tests__/__generated__/RelayResolverModelWithContextTestQuery.graphql.js new file mode 100644 index 0000000000000..b8ea609ee7262 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/RelayResolverModelWithContextTestQuery.graphql.js @@ -0,0 +1,215 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ClientRequest, ClientQuery } from 'relay-runtime'; +import type { DataID } from "relay-runtime"; +import type { RelayResolverModelWithContextTestFragment$fragmentType } from "./RelayResolverModelWithContextTestFragment.graphql"; +import {todo_model as queryTodoModelResolverType} from "../../../relay-runtime/store/__tests__/resolvers/QueryTodoModel.js"; +import type { TestResolverContextType } from "../../../relay-runtime/mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `queryTodoModelResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryTodoModelResolverType: ( + args: {| + todoID: string, + |}, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +export type RelayResolverModelWithContextTestQuery$variables = {| + id: string, +|}; +export type RelayResolverModelWithContextTestQuery$data = {| + +todo_model: ?{| + +$fragmentSpreads: RelayResolverModelWithContextTestFragment$fragmentType, + |}, +|}; +export type RelayResolverModelWithContextTestQuery = {| + response: RelayResolverModelWithContextTestQuery$data, + variables: RelayResolverModelWithContextTestQuery$variables, +|}; +*/ + +var node/*: ClientRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "todoID", + "variableName": "id" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "kind": "InlineFragment", + "selections": [ + { + "name": "__relay_model_instance", + "args": null, + "fragment": { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/) + ], + "type": "TodoModel", + "abstractKey": null + }, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false + } + ], + "type": "TodoModel", + "abstractKey": null +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "RelayResolverModelWithContextTestQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "concreteType": "TodoModel", + "modelResolvers": { + "TodoModel": { + "alias": null, + "args": [], + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "TodoModel__id" + }, + "kind": "RelayLiveResolver", + "name": "todo_model", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./../../../relay-runtime/store/__tests__/resolvers/__generated__/TodoModel__id.graphql'), require('./../../../relay-runtime/store/__tests__/resolvers/TodoModel').TodoModel, 'id', true), + "path": "todo_model.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": (v1/*: any*/), + "fragment": null, + "kind": "RelayResolver", + "name": "todo_model", + "resolverModule": require('./../../../relay-runtime/store/__tests__/resolvers/QueryTodoModel').todo_model, + "path": "todo_model" + }, + "linkedField": { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TodoModel", + "kind": "LinkedField", + "name": "todo_model", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "RelayResolverModelWithContextTestFragment" + } + ], + "storageKey": null + } + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "RelayResolverModelWithContextTestQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "backingField": { + "name": "todo_model", + "args": (v1/*: any*/), + "fragment": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false + }, + "linkedField": { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TodoModel", + "kind": "LinkedField", + "name": "todo_model", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "name": "description", + "args": null, + "fragment": (v3/*: any*/), + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + }, + { + "name": "another_value_from_context", + "args": null, + "fragment": (v3/*: any*/), + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + } + ], + "storageKey": null + } + } + ] + }, + "params": { + "cacheID": "0196832cb242ac4177d6b6eede119e96", + "id": null, + "metadata": {}, + "name": "RelayResolverModelWithContextTestQuery", + "operationKind": "query", + "text": null + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "5322e368bc0ab0fd2107e5680043ba4c"; +} + +module.exports = ((node/*: any*/)/*: ClientQuery< + RelayResolverModelWithContextTestQuery$variables, + RelayResolverModelWithContextTestQuery$data, +>*/); diff --git a/packages/react-relay/buildReactRelayContainer.js b/packages/react-relay/buildReactRelayContainer.js index f425c44635028..d9ae779263252 100644 --- a/packages/react-relay/buildReactRelayContainer.js +++ b/packages/react-relay/buildReactRelayContainer.js @@ -28,15 +28,15 @@ const {getFragment} = require('relay-runtime'); const {useContext} = React; type ContainerCreator = ( - Component: React.ComponentType, + Component: component(...any), fragments: FragmentMap, -) => React.ComponentType; +) => component(...any); /** * Helper to create the Relay HOCs with ref forwarding, setting the displayName * and reading the React context. */ -function buildReactRelayContainer>( +function buildReactRelayContainer( ComponentClass: TBase, fragmentSpec: GeneratedNodeMap, createContainerWithFragments: ContainerCreator, diff --git a/packages/react-relay/index.js b/packages/react-relay/index.js index a9e1520fd96e7..238e8d1a39d7d 100644 --- a/packages/react-relay/index.js +++ b/packages/react-relay/index.js @@ -28,7 +28,7 @@ const useFragment = require('./relay-hooks/useFragment'); const useLazyLoadQuery = require('./relay-hooks/useLazyLoadQuery'); const useMutation = require('./relay-hooks/useMutation'); const usePaginationFragment = require('./relay-hooks/usePaginationFragment'); -const usePrefetchableForwardPaginationFragment_EXPERIMENTAL = require('./relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL'); +const usePrefetchableForwardPaginationFragment = require('./relay-hooks/usePrefetchableForwardPaginationFragment'); const usePreloadedQuery = require('./relay-hooks/usePreloadedQuery'); const useQueryLoader = require('./relay-hooks/useQueryLoader'); const useRefetchableFragment = require('./relay-hooks/useRefetchableFragment'); @@ -126,8 +126,8 @@ module.exports = { usePaginationFragment: usePaginationFragment, usePreloadedQuery: usePreloadedQuery, useRefetchableFragment: useRefetchableFragment, - usePrefetchableForwardPaginationFragment_EXPERIMENTAL: - usePrefetchableForwardPaginationFragment_EXPERIMENTAL, + usePrefetchableForwardPaginationFragment: + usePrefetchableForwardPaginationFragment, useRelayEnvironment: useRelayEnvironment, useSubscribeToInvalidationState: useSubscribeToInvalidationState, useSubscription: useSubscription, diff --git a/packages/react-relay/multi-actor/__tests__/ActorChange-test.js b/packages/react-relay/multi-actor/__tests__/ActorChange-test.js index 23a25aae17b92..02011bb8aea61 100644 --- a/packages/react-relay/multi-actor/__tests__/ActorChange-test.js +++ b/packages/react-relay/multi-actor/__tests__/ActorChange-test.js @@ -185,6 +185,7 @@ describe('ActorChange', () => { ); }); + // $FlowFixMe[cannot-resolve-name] skipIf(process.env.OSS, 'should render a fragment for actor', () => { fetchFnForActor = jest.fn(actorId => Observable.from( @@ -286,6 +287,7 @@ describe('ActorChange', () => { }); skipIf( + // $FlowFixMe[cannot-resolve-name] process.env.OSS, 'should send a query and mutations with correct actor id, from the correct environment', () => { diff --git a/packages/react-relay/relay-hooks/EntryPointContainer.react.js b/packages/react-relay/relay-hooks/EntryPointContainer.react.js index 669b776f0085c..35a86164b9e5a 100644 --- a/packages/react-relay/relay-hooks/EntryPointContainer.react.js +++ b/packages/react-relay/relay-hooks/EntryPointContainer.react.js @@ -22,29 +22,25 @@ const React = require('react'); const {useContext, useEffect} = require('react'); const warning = require('warning'); -function EntryPointContainer< +component EntryPointContainer< // $FlowFixMe[unsupported-variance-annotation] - +TPreloadedQueries: {...}, + TRuntimeProps: {...}, + TRenders: React.Node, // $FlowFixMe[unsupported-variance-annotation] - +TPreloadedNestedEntryPoints: {...}, - // $FlowFixMe[unsupported-variance-annotation] - +TRuntimeProps: {...}, - // $FlowFixMe[unsupported-variance-annotation] - +TExtraProps, - // $FlowFixMe[unsupported-variance-annotation] - +TEntryPointComponent: EntryPointComponent< - TPreloadedQueries, - TPreloadedNestedEntryPoints, + TEntryPointComponent: EntryPointComponent< + // $FlowExpectedErrors[unclear-type] Use any to accept all kinds of EntryPointComponent + any, + // $FlowExpectedErrors[unclear-type] Use any to accept all kinds of EntryPointComponent + any, TRuntimeProps, - TExtraProps, + // $FlowExpectedErrors[unclear-type] Use any to accept all kinds of EntryPointComponent + any, + TRenders, >, ->({ - entryPointReference, - props, -}: $ReadOnly<{ +>( entryPointReference: PreloadedEntryPoint, props: TRuntimeProps, -}>): React.MixedElement { +) renders TRenders { warning( entryPointReference.isDisposed === false, ': Expected entryPointReference to not be disposed ' + diff --git a/packages/react-relay/relay-hooks/EntryPointTypes.flow.js b/packages/react-relay/relay-hooks/EntryPointTypes.flow.js index 85001ea7c9ac6..eb46ec5ea948a 100644 --- a/packages/react-relay/relay-hooks/EntryPointTypes.flow.js +++ b/packages/react-relay/relay-hooks/EntryPointTypes.flow.js @@ -36,6 +36,7 @@ export type PreloadFetchPolicy = export type PreloadOptions = { +fetchKey?: string | number, +fetchPolicy?: ?PreloadFetchPolicy, + +includeIf?: ?boolean, +networkCacheConfig?: ?CacheConfig, }; @@ -178,14 +179,15 @@ export type EntryPointComponent< TPreloadedEntryPoints = {}, TRuntimeProps = {}, TExtraProps = null, -> = ComponentType< - EntryPointProps< + TRenders: React.Node = React.Node, +> = component( + ...EntryPointProps< TPreloadedQueries, TPreloadedEntryPoints, TRuntimeProps, TExtraProps, - >, ->; + > +) renders TRenders; // Return type of the `getPreloadProps(...)` of the entry point export type PreloadProps< diff --git a/packages/react-relay/relay-hooks/MatchContainer.js b/packages/react-relay/relay-hooks/MatchContainer.js index dc59daefbcde6..fba82f009063c 100644 --- a/packages/react-relay/relay-hooks/MatchContainer.js +++ b/packages/react-relay/relay-hooks/MatchContainer.js @@ -95,7 +95,7 @@ export type MatchPointer = { export type MatchContainerProps = { +fallback?: ?TFallback, - +loader: (module: mixed) => React.ComponentType, + +loader: (module: mixed) => component(...TProps), +match: ?MatchPointer | ?TypenameOnlyPointer, +props?: TProps, }; diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResource-ClientEdges-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResource-ClientEdges-test.js index 29cbc7a52afa6..d0935d63a4765 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResource-ClientEdges-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResource-ClientEdges-test.js @@ -32,7 +32,7 @@ const BASIC_QUERY = graphql` query FragmentResourceClientEdgesTest1Query($id: ID!) { node(id: $id) { __typename - ...FragmentResourceClientEdgesTestFragment1 + ...FragmentResourceClientEdgesTestFragment1 @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResource-Resolver-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResource-Resolver-test.js index 9bcff17ec7e50..2aaffb99ae0d9 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResource-Resolver-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResource-Resolver-test.js @@ -34,7 +34,7 @@ const BASIC_QUERY = graphql` query FragmentResourceResolverTest1Query($id: ID!) { node(id: $id) { __typename - ...FragmentResourceClientEdgesTestFragment1 + ...FragmentResourceClientEdgesTestFragment1 @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResource-SemanticNonNull-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResource-SemanticNonNull-test.js index c857854450fdd..a81359c1998e7 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResource-SemanticNonNull-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResource-SemanticNonNull-test.js @@ -62,7 +62,9 @@ beforeEach(() => { node(id: $id) { __typename ...FragmentResourceSemanticNonNullTestFragment1 + @dangerously_unaliased_fixme ...FragmentResourceSemanticNonNullTestFragment2 + @dangerously_unaliased_fixme } } `, diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTracker-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTracker-test.js index d28ed063e2c95..a2ec8feb71fdc 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTracker-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTracker-test.js @@ -70,6 +70,7 @@ describe.each([true, false])( query FragmentResourceWithOperationTrackerTestNodeQuery($id: ID!) { node(id: $id) { ...FragmentResourceWithOperationTrackerTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerOptimisticUpdates-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerOptimisticUpdates-test.js index 6cca0ac01238e..bf99d984ee0cc 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerOptimisticUpdates-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerOptimisticUpdates-test.js @@ -61,6 +61,7 @@ describe('FragmentResource with Operation Tracker for optimistic updates behavio node(id: $id) { __typename ...FragmentResourceWithOperationTrackerOptimisticUpdatesTestFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerSuspense-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerSuspense-test.js index 77211d64c1473..a0b7648286b05 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerSuspense-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResource-WithOperationTrackerSuspense-test.js @@ -64,6 +64,7 @@ describe('FragmentResource with Operation Tracker and Suspense behavior', () => node(id: $id) { __typename ...FragmentResourceWithOperationTrackerSuspenseTestFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResource-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResource-test.js index 1318e1adec816..a9948a923d1fe 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResource-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResource-test.js @@ -160,7 +160,7 @@ describe('FragmentResource', () => { query FragmentResourceTest1Query($id: ID!) { node(id: $id) { __typename - ...FragmentResourceTest1Fragment + ...FragmentResourceTest1Fragment @dangerously_unaliased_fixme } } `; @@ -176,7 +176,7 @@ describe('FragmentResource', () => { query FragmentResourceTest2Query($id: ID!) { node(id: $id) { __typename - ...FragmentResourceTest2Fragment + ...FragmentResourceTest2Fragment @dangerously_unaliased_fixme } } `; @@ -449,7 +449,7 @@ describe('FragmentResource', () => { node(id: $id) { __typename name @include(if: $foo) - ...FragmentResourceTest6Fragment + ...FragmentResourceTest6Fragment @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/FragmentResourceRequiredField-test.js b/packages/react-relay/relay-hooks/__tests__/FragmentResourceRequiredField-test.js index 93f21e192d822..8f8cffbb03c35 100644 --- a/packages/react-relay/relay-hooks/__tests__/FragmentResourceRequiredField-test.js +++ b/packages/react-relay/relay-hooks/__tests__/FragmentResourceRequiredField-test.js @@ -56,6 +56,7 @@ beforeEach(() => { node(id: $id) { __typename ...FragmentResourceRequiredFieldTestUserFragment + @dangerously_unaliased_fixme } } `, diff --git a/packages/react-relay/relay-hooks/__tests__/LazyLoadEntryPointContainer_DEEPRECATED-test.js b/packages/react-relay/relay-hooks/__tests__/LazyLoadEntryPointContainer_DEEPRECATED-test.js index fb352876c4767..9e5e2e90fbb8f 100644 --- a/packages/react-relay/relay-hooks/__tests__/LazyLoadEntryPointContainer_DEEPRECATED-test.js +++ b/packages/react-relay/relay-hooks/__tests__/LazyLoadEntryPointContainer_DEEPRECATED-test.js @@ -133,7 +133,7 @@ beforeEach(() => { }); params = { - kind: 'PreloadableConcreteRequest', + kind: 'PreloadableConcreteRequest' as const, params: query.params, }; entryPoint = { @@ -269,6 +269,7 @@ it.skip('suspends then updates when the query and component load', () => { expect(entryPoint.root.load).toBeCalledTimes(1); expect(receivedProps).not.toBe(null); expect(receivedProps?.props).toBe(otherProps); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Zuck'); }); @@ -355,6 +356,7 @@ it('re-renders without reloading when non-prefetch props change', () => { , ); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Zuck'); expect(Component).toBeCalledTimes(2); expect(entryPoint.getPreloadProps).toBeCalledTimes(1); @@ -404,6 +406,7 @@ it.skip('re-renders and reloads when prefetch params change', () => { , ); }); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Fallback'); expect(Component).toBeCalledTimes(2); expect(entryPoint.getPreloadProps).toBeCalledTimes(2); @@ -422,6 +425,7 @@ it.skip('re-renders and reloads when prefetch params change', () => { }); dataSource.complete(); TestRenderer.act(() => jest.runAllImmediates()); + // $FlowFixMe[incompatible-use] expect(renderer.toJSON()).toEqual('Mark'); }); diff --git a/packages/react-relay/relay-hooks/__tests__/MatchContainer-test.js b/packages/react-relay/relay-hooks/__tests__/MatchContainer-test.js index 26c434d30714b..e49a58b6e958b 100644 --- a/packages/react-relay/relay-hooks/__tests__/MatchContainer-test.js +++ b/packages/react-relay/relay-hooks/__tests__/MatchContainer-test.js @@ -53,7 +53,7 @@ describe('MatchContainer', () => { beforeEach(() => { jest.resetModules(); - loader = jest.fn<[mixed], React.ComponentType>(); + loader = jest.fn<[mixed], component(...any)>(); // $FlowFixMe[missing-local-annot] error found when enabling Flow LTI mode UserComponent = jest.fn(props => (

diff --git a/packages/react-relay/relay-hooks/__tests__/QueryResource-test.js b/packages/react-relay/relay-hooks/__tests__/QueryResource-test.js index 650f373e77859..89e4e60acae58 100644 --- a/packages/react-relay/relay-hooks/__tests__/QueryResource-test.js +++ b/packages/react-relay/relay-hooks/__tests__/QueryResource-test.js @@ -11,7 +11,7 @@ 'use strict'; -import type {FetchPolicy, Subscription} from 'relay-runtime'; +import type {FetchPolicy, RenderPolicy, Subscription} from 'relay-runtime'; const {getQueryResourceForEnvironment} = require('../QueryResource'); const { @@ -35,7 +35,7 @@ disallowConsoleErrors(); describe('QueryResource', () => { let environment; let QueryResource; - let fetchPolicy; + let fetchPolicy: FetchPolicy; let fetchObservable; let fetchObservableMissingData; let fetchObserverableLiveMissingData; @@ -46,7 +46,7 @@ describe('QueryResource', () => { let liveQueryMissingData; let gqlLiveQueryMissingData; let release; - let renderPolicy; + let renderPolicy: RenderPolicy; let store; const variables = { id: '4', @@ -414,7 +414,7 @@ describe('QueryResource', () => { query QueryResourceTest3Query($id: ID!) { node(id: $id) { __typename - ...QueryResourceTest1Fragment + ...QueryResourceTest1Fragment @dangerously_unaliased_fixme } } `; @@ -472,7 +472,7 @@ describe('QueryResource', () => { query QueryResourceTest4Query($id: ID!) { node(id: $id) { __typename - ...QueryResourceTest2Fragment + ...QueryResourceTest2Fragment @dangerously_unaliased_fixme } } `; @@ -528,7 +528,7 @@ describe('QueryResource', () => { query QueryResourceTest5Query($id: ID!) { node(id: $id) { __typename - ...QueryResourceTest3Fragment + ...QueryResourceTest3Fragment @dangerously_unaliased_fixme } } `; @@ -884,7 +884,7 @@ describe('QueryResource', () => { query QueryResourceTest6Query($id: ID!) { node(id: $id) { __typename - ...QueryResourceTest4Fragment + ...QueryResourceTest4Fragment @dangerously_unaliased_fixme } } `; @@ -942,7 +942,7 @@ describe('QueryResource', () => { query QueryResourceTest7Query($id: ID!) { node(id: $id) { __typename - ...QueryResourceTest5Fragment + ...QueryResourceTest5Fragment @dangerously_unaliased_fixme } } `; @@ -998,7 +998,9 @@ describe('QueryResource', () => { node(id: $id) { __typename id - ...QueryResourceTest6Fragment @defer + ...QueryResourceTest6Fragment + @dangerously_unaliased_fixme + @defer } } `; @@ -2892,7 +2894,7 @@ describe('QueryResource, with an environment meant for SSR', () => { let gqlQuery; let query; let release; - let renderPolicy; + let renderPolicy: RenderPolicy; const variables = { id: '4', }; diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceClientEdgesTest1Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceClientEdgesTest1Query.graphql.js index 75ed6ddf7ad1b..b531285de8993 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceClientEdgesTest1Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceClientEdgesTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<0a547f35f5a76a3b0a391aa204a5858d>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -151,7 +151,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a45d5fe34c226d737ff1adb0205a4141"; + (node/*: any*/).hash = "12b2f7755a7f2800f27cf07a3b735b7f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceRequiredFieldTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceRequiredFieldTestUserQuery.graphql.js index f879414d3ea2f..38adbaaff3cc7 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceRequiredFieldTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceRequiredFieldTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<46550cd0d6791b7406a22bdbf66a6def>> + * @generated SignedSource<<210e2d96d0e20787747f361efbcfb67f>> * @flow * @lightSyntaxTransform * @nogrep @@ -144,7 +144,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "d8c62e66c365d6179520bf2a12a9f8ac"; + (node/*: any*/).hash = "4d73d93e8b781ced6ccafcf8d0b963e7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceResolverTest1Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceResolverTest1Query.graphql.js index d7b7d345b1c03..9ff6351b49ee5 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceResolverTest1Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceResolverTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<92f8ffd1c3c7db7f5dfbe80710eee93f>> * @flow * @lightSyntaxTransform * @nogrep @@ -151,7 +151,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "e5738684a7645492621dd008c800ee24"; + (node/*: any*/).hash = "8255413a07b7c7f7caeb7dd17db86835"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceSemanticNonNullTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceSemanticNonNullTestQuery.graphql.js index 9df00e206ca39..eae336860c7ae 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceSemanticNonNullTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceSemanticNonNullTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9edf937671528fb8914422019bada16e>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -143,7 +143,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "79609fa487e20403b5757ec5fe030446"; + (node/*: any*/).hash = "530d4a1ded82952de97544eaa016b219"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest1Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest1Query.graphql.js index ac513a45ce13d..13b436b2dc353 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest1Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<55a15f486d0a77f5d41718c1277d9c19>> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "bf5cd6051d37288b658f3312de8c527a"; + (node/*: any*/).hash = "cc7b893d1f91ada940b65acd486ebdf8"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest2Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest2Query.graphql.js index 5753ef2113af7..0c5dc8aaa6267 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest2Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest2Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<492f5a13adcdccae4ff4c0c25d2bd98a>> + * @generated SignedSource<<08a13fc9537b8da73c09d9b783f91a65>> * @flow * @lightSyntaxTransform * @nogrep @@ -144,7 +144,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "9485c8a47f2c7a7fa324c0997ffc6869"; + (node/*: any*/).hash = "3dcce69a04edf144de4803ff886fd056"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest6Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest6Query.graphql.js index 4cdcdc4c94585..2557207e8620b 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest6Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<727afb0fdaccca2f20b0f1be83b1eaec>> + * @generated SignedSource<<50516fea5aed3c47306f84a03c246326>> * @flow * @lightSyntaxTransform * @nogrep @@ -157,7 +157,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "6729d563666fcfaad04fef9ac67fe82f"; + (node/*: any*/).hash = "b3516b8d8ace6d328f7c9b16fbbd16e7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerOptimisticUpdatesTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerOptimisticUpdatesTestQuery.graphql.js index 91382633a1dc1..03cf46501b39b 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerOptimisticUpdatesTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerOptimisticUpdatesTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<74a5dbdc8516bd27deb03e9589c5ec06>> + * @generated SignedSource<<43667d825dc762821b93c44a4fd2ece1>> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "14c673af170df5bad4f4905bb7368415"; + (node/*: any*/).hash = "92ff47cf9f81c373192ab8d76a50f574"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerSuspenseTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerSuspenseTestQuery.graphql.js index f8c4e905bb48e..dc9fe06d34f99 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerSuspenseTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerSuspenseTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<3913d108171e606ef0523ee539b2b4f1>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "cbef95bbb7223d9a6dca6b4123ef5730"; + (node/*: any*/).hash = "b3105aa8587f88e054af71980209e680"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerTestNodeQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerTestNodeQuery.graphql.js index ee949e0273c3d..93b9a393e051e 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerTestNodeQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/FragmentResourceWithOperationTrackerTestNodeQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<52a8c1b75facb93f5014c33c45de06a7>> + * @generated SignedSource<<19fc9778d41a62d22c998b391918e9b3>> * @flow * @lightSyntaxTransform * @nogrep @@ -216,7 +216,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "e4c3c9f6213e6aca299a02aff58349e3"; + (node/*: any*/).hash = "43da25d82b333c14f0570f553ebc8631"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest3Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest3Query.graphql.js index d6b8573624162..2e4585a127ea8 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest3Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest3Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<21b0ced9a0271e12434a3f814023dba7>> + * @generated SignedSource<<4a36a85370be58e4d9e3e17e3e20c554>> * @flow * @lightSyntaxTransform * @nogrep @@ -123,7 +123,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "0cdada5db8e942ed6d118885802edcc4"; + (node/*: any*/).hash = "08191eeb9de0fb6b85b5e9abeb33bd0e"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest4Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest4Query.graphql.js index 142a5db12658d..c36a8b2ef906c 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest4Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest4Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<0be85a4f15a03050729c4a354df810aa>> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f60bd73c9198b5edbb1b218d58b8828b"; + (node/*: any*/).hash = "988e78fe20f9d313094ef46433092ce7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest5Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest5Query.graphql.js index f1ab23fdb88e2..6ce5d9775626c 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest5Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest5Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<8a9e361f30759be638a0e58e54d2744b>> + * @generated SignedSource<<4baa57782add3272b9ce912cc50f3270>> * @flow * @lightSyntaxTransform * @nogrep @@ -123,7 +123,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "602fa3055d2ebb555eef09c120f95c19"; + (node/*: any*/).hash = "1db024536cad50b8dffa9214614b980e"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest6Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest6Query.graphql.js index 8bfb231204a21..691d51611a3cd 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest6Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -123,7 +123,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "2aadb7307400e7819f52bcdad17c5301"; + (node/*: any*/).hash = "19bc0d618b5dced35c705f3ba789fdd6"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest7Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest7Query.graphql.js index 15591f92b2583..9126f24f3190f 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest7Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest7Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<48ac33e8d5ff8d8979d680e1e90b67c8>> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "bf937ab1046354c4b80e3a07597b4bfa"; + (node/*: any*/).hash = "256baee2dce2b172d5cf955589c1ab8f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest8Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest8Query.graphql.js index 87725a6d5fc8d..193a4d3f6d86c 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest8Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/QueryResourceTest8Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<34539f71f610e0639e8dd0eeee091643>> * @flow * @lightSyntaxTransform * @nogrep @@ -153,7 +153,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "6e87df11edb8826c7aad49628ee3bb71"; + (node/*: any*/).hash = "5e0f54bce33d434141c59d68d5c52013"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/preloadQueryDEPRECATEDTest_ProvidedVarQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/preloadQueryDEPRECATEDTest_ProvidedVarQuery.graphql.js index 7fa7134a61359..45ee3d531cabf 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/preloadQueryDEPRECATEDTest_ProvidedVarQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/preloadQueryDEPRECATEDTest_ProvidedVarQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<86703500dd187dcf27128bbe814cb96b>> * @flow * @lightSyntaxTransform * @nogrep @@ -210,7 +210,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "949cb1280a8579bbc809976fd4ed18c6"; + (node/*: any*/).hash = "4979a880c3f4961191919f23c6de8c42"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQuery.graphql.js index 48c79b864c2b4..c2773696af3df 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<2b24879dbe7d70ef4f82329d7920aa18>> + * @generated SignedSource<<81e3953d5a549a21fb4c20a9bb9f79e6>> * @flow * @lightSyntaxTransform * @nogrep @@ -328,7 +328,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "24a79476464a446cf23640ec65b6850f"; + (node/*: any*/).hash = "56876e3affcf427dac0fddd361ed0707"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js index cd6d8f769b7f4..49cec7d79a056 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<60642da297baaa6e036f8ad58d2e74b4>> + * @generated SignedSource<<8e59b06a123a216465358c6af67591d1>> * @flow * @lightSyntaxTransform * @nogrep @@ -354,7 +354,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "19018d89e0c127bfa85e874e07a4b743"; + (node/*: any*/).hash = "82ec6417d1b5231f70f297af02cfa3e9"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js index d5a7f723adbb7..80bb0a4621c9c 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<4e6f2e06315d1a96223ff40ed272a7a7>> + * @generated SignedSource<<5f766aedba037b882a891998cbc21dee>> * @flow * @lightSyntaxTransform * @nogrep @@ -314,7 +314,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "48433b64c70ecbb519ed6a7d45ec3952"; + (node/*: any*/).hash = "43b6d41944fcdea59eebc1d5f59fe65c"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithoutIDQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithoutIDQuery.graphql.js index 9d305ddf3f1f7..963e977110c53 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithoutIDQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentTestUserQueryWithoutIDQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<3f1bf507d7b273a2047f88b3384d35a1>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -337,7 +337,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f5f7783184358dbce0a1bd2544fdddd4"; + (node/*: any*/).hash = "259619db11a4a82a8c105f3462338e2b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQuery.graphql.js index 416106de396e7..b5fc635c778a2 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<57ed9b4c4ffc0e3b54a7e5397cb3e191>> * @flow * @lightSyntaxTransform * @nogrep @@ -354,7 +354,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "d89c8846126eef2be90954dd65755d31"; + (node/*: any*/).hash = "5ec19807252bd1d9073922445aefa2a8"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQueryWithoutIDQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQueryWithoutIDQuery.graphql.js index 5bad8df4519c1..a065a109eef40 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQueryWithoutIDQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useBlockingPaginationFragmentWithSuspenseTransitionTestUserQueryWithoutIDQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9cfdf56c655590459bfac06d65fcc5bc>> + * @generated SignedSource<<534e25badb1599dfe036b7f761a950c9>> * @flow * @lightSyntaxTransform * @nogrep @@ -337,7 +337,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "8d3ec6e6a62b839f261ad74ddca4588a"; + (node/*: any*/).hash = "82c3921e9fe483d213ac9b7581afd1de"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useEntryPointLoaderReactDoubleEffectsTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useEntryPointLoaderReactDoubleEffectsTestUserQuery.graphql.js index 3e46026e1aea4..8d4dd9cd82fe7 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useEntryPointLoaderReactDoubleEffectsTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useEntryPointLoaderReactDoubleEffectsTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<3ca775c4cf21029abec02867b8b46c0f>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -133,7 +133,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "d296fc0f253f3d0b6940f48b0e01845e"; + (node/*: any*/).hash = "6b7f3606d43827b1210a7de7c6a81556"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeReactDoubleEffectsTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeReactDoubleEffectsTestUserQuery.graphql.js index d46e17712dec2..c1df40f17accf 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeReactDoubleEffectsTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeReactDoubleEffectsTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6124b7833cd3997376d25200238af31e>> + * @generated SignedSource<<6e54926b33fa38bd596e1b7b0b314562>> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "362966f1b2b2a5e926134b5ad581e901"; + (node/*: any*/).hash = "8558f0f05b05382bdd2044c0b2e5f4e6"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeRequiredTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeRequiredTestUserQuery.graphql.js index bde7893d275f2..a1c5bb3bfe2bd 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeRequiredTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeRequiredTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<717bc84de90168f0b2ea717596fe8145>> + * @generated SignedSource<<7730fe0ebb5b361b1703da8bdaf0ac6d>> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "fc7ae7325babad6ab4c2fbda74adc09d"; + (node/*: any*/).hash = "681f0f81107d574d43702ccd528a3a71"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeTestUserQuery.graphql.js index 60e7561472507..f654acdf6d942 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentNodeTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<2b2e9dd521238896ef66b278c2a11075>> + * @generated SignedSource<<1b9cd4b4e3f5731a7f403eb88a70d3c4>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "84829266b419cba0d2a2e681f3d1db63"; + (node/*: any*/).hash = "1445e0037c0bb573c2ca3f35d1f84cf7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentTestUserQuery.graphql.js index f50d2fe6ef87a..19064abe601bb 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<33b44471531b2bc8bc4ca6f476203cc6>> * @flow * @lightSyntaxTransform * @nogrep @@ -141,7 +141,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "b7cb456d0fac348a436c061eb926e10b"; + (node/*: any*/).hash = "3b73e10cf16353d2ea6f653510d3874b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithOperationTrackerSuspenseTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithOperationTrackerSuspenseTestQuery.graphql.js index 5d366ce3fdbed..c5abc2c47a70c 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithOperationTrackerSuspenseTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithOperationTrackerSuspenseTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<3c807f2294b482947010f72e07e490a2>> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "d9a040d89152cefea35ea45be32edaa5"; + (node/*: any*/).hash = "d21e697bfd19cd686c5039c4a5d8d27f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithRequiredTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithRequiredTestQuery.graphql.js index b712fb7ca1959..d43d571dad5d7 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithRequiredTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useFragmentWithRequiredTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<15c3c6b4bed449af7f25913d945cc922>> * @flow * @lightSyntaxTransform * @nogrep @@ -141,7 +141,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "66a4cfb191113d8dc82023073e6a8884"; + (node/*: any*/).hash = "13a5758b6ca5410f0169950b83543b47"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserDeferQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserDeferQuery.graphql.js index 2a64ff619c67b..eb7b1ce5ba662 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserDeferQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserDeferQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<8b64ffb21bc96f31e1e05c0d81d28cf2>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "4bd5e517a288bf4fcf9d2330b6d2e13e"; + (node/*: any*/).hash = "567eaed2bb0068576063e236f9b4560a"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserQuery.graphql.js index a6b4afe967b4b..0c438c9bfc675 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useIsParentQueryActiveTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f41a54a0c430c98e7f9e1975a2cfac15"; + (node/*: any*/).hash = "6eb3252eb53f89ed77bbdecca56eae94"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeActivityTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeActivityTestUserQuery.graphql.js index c8581a4d68cc7..afec39c547259 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeActivityTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeActivityTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<3a12553b8e168fce15387920b230a522>> + * @generated SignedSource<<793498f577ba19175f5e0da7d6fd9a12>> * @flow * @lightSyntaxTransform * @nogrep @@ -133,7 +133,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "63bb781a6f6d4114078c8e85d80b9bc9"; + (node/*: any*/).hash = "666cde58381d36fc1cad522b6da4cbb7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeFastRefreshTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeFastRefreshTestUserQuery.graphql.js index 9cdb20c4c3517..a5112f95a0f8e 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeFastRefreshTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeFastRefreshTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<913362b6843cb785f7c89ccea96009e1>> + * @generated SignedSource<<25d516731ff8d6871063f2816fe6257e>> * @flow * @lightSyntaxTransform * @nogrep @@ -133,7 +133,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "ee05f828677e819fb1cfd6cf12c4e4a0"; + (node/*: any*/).hash = "bccaba4f51a130fa4e7c4a7c52677c9e"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQuery.graphql.js index 4d969ab32e51c..c16f58718ace1 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<476545c9feafe66809f18fbe494f99a4>> + * @generated SignedSource<<025dbd59ac7c6543a42c631b492d5554>> * @flow * @lightSyntaxTransform * @nogrep @@ -147,7 +147,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "4f5221aaf962b9f3544c53ae0f65d8cd"; + (node/*: any*/).hash = "231f94302ea2eb1609d41079dda967f2"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQueryWithDeferQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQueryWithDeferQuery.graphql.js index 42852a7734e01..929f4b652afdc 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQueryWithDeferQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeReactDoubleEffectsTestUserQueryWithDeferQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<608044f18e7cb808fde148f334053945>> * @flow * @lightSyntaxTransform * @nogrep @@ -159,7 +159,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "12d18891ad074f33e2e0064f4d26ebd2"; + (node/*: any*/).hash = "6e60686779f65e9c9b3369261f936944"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTest1Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTest1Query.graphql.js index 5c99d2c1327f1..b12fb0506c666 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTest1Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<2a197f4fec9a47a0a82d656e9f19d028>> + * @generated SignedSource<<96c27eb2caa81b47f2f9108024d7017b>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "021b10a8f84891aa446aeda4b318a341"; + (node/*: any*/).hash = "7dace47991244c4c8a38b786cf8e85c4"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTestUserQuery.graphql.js index 7de63a79abbea..940aa87224201 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useLazyLoadQueryNodeTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<38b9916cd4425d8a094c80b4a29ba659>> + * @generated SignedSource<<282ca852f80210afbdc477b340e37aae>> * @flow * @lightSyntaxTransform * @nogrep @@ -133,7 +133,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "bc3d98c6a2a45e4247e409cca1d3f06f"; + (node/*: any*/).hash = "19ad769206887ea7a7b87d2855e4cc1f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryFragment.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryFragment.graphql.js index b5449c614b58f..1e5f7b7dd2921 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryFragment.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryFragment.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<78d2548c61fb6ef49166b87871b6e52c>> + * @generated SignedSource<<2e4ae25f68052d1b3f1d5a0327a06554>> * @flow * @lightSyntaxTransform * @nogrep @@ -22,7 +22,6 @@ import type { FragmentType } from "relay-runtime"; declare export opaque type usePaginationFragmentTestStoryFragment$fragmentType: FragmentType; type usePaginationFragmentTestStoryFragmentRefetchQuery$variables = any; export type usePaginationFragmentTestStoryFragment$data = {| - +__token: string, +comments: ?{| +edges: ?$ReadOnlyArray> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -221,13 +221,6 @@ return { "name": "fetch_id", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null - }, (v3/*: any*/) ], "storageKey": null @@ -235,12 +228,12 @@ return { ] }, "params": { - "cacheID": "141601b4d00333b2f388709fff638ee6", + "cacheID": "16690aeca128c15136cb3c656e061799", "id": null, "metadata": {}, "name": "usePaginationFragmentTestStoryFragmentRefetchQuery", "operationKind": "query", - "text": "query usePaginationFragmentTestStoryFragmentRefetchQuery(\n $count: Int = 10\n $cursor: ID\n $id: ID!\n) {\n fetch__NonNodeStory(input_fetch_id: $id) {\n ...usePaginationFragmentTestStoryFragment_1G22uz\n id\n }\n}\n\nfragment usePaginationFragmentTestStoryFragment_1G22uz on NonNodeStory {\n comments(first: $count, after: $cursor) {\n edges {\n node {\n id\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n fetch_id\n __token\n}\n" + "text": "query usePaginationFragmentTestStoryFragmentRefetchQuery(\n $count: Int = 10\n $cursor: ID\n $id: ID!\n) {\n fetch__NonNodeStory(input_fetch_id: $id) {\n ...usePaginationFragmentTestStoryFragment_1G22uz\n id\n }\n}\n\nfragment usePaginationFragmentTestStoryFragment_1G22uz on NonNodeStory {\n comments(first: $count, after: $cursor) {\n edges {\n node {\n id\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n fetch_id\n}\n" } }; })(); diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryQuery.graphql.js index 0d0a48db67a14..12156d2f48991 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestStoryQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<6f9740295cde0d77668c74f29279d7cc>> * @flow * @lightSyntaxTransform * @nogrep @@ -192,13 +192,6 @@ return { "name": "fetch_id", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null - }, (v3/*: any*/) ], "storageKey": null @@ -206,12 +199,12 @@ return { ] }, "params": { - "cacheID": "4f3e70176552d390bebe4d2886c17745", + "cacheID": "3cb446084b7d394d00b3150a5ce104cb", "id": null, "metadata": {}, "name": "usePaginationFragmentTestStoryQuery", "operationKind": "query", - "text": "query usePaginationFragmentTestStoryQuery(\n $id: ID!\n) {\n nonNodeStory(id: $id) {\n ...usePaginationFragmentTestStoryFragment\n id\n }\n}\n\nfragment usePaginationFragmentTestStoryFragment on NonNodeStory {\n comments(first: 10) {\n edges {\n node {\n id\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n fetch_id\n __token\n}\n" + "text": "query usePaginationFragmentTestStoryQuery(\n $id: ID!\n) {\n nonNodeStory(id: $id) {\n ...usePaginationFragmentTestStoryFragment\n id\n }\n}\n\nfragment usePaginationFragmentTestStoryFragment on NonNodeStory {\n comments(first: 10) {\n edges {\n node {\n id\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n fetch_id\n}\n" } }; })(); diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQuery.graphql.js index 82dfc5b1eebe1..85d3fc89c72f6 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<88786543dd9768adb7f4aba8bb9b94ea>> + * @generated SignedSource<<9a72ecaa8efe53949809b54f7d7ae1c4>> * @flow * @lightSyntaxTransform * @nogrep @@ -328,7 +328,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "e6459baa3fc32eef6945070272ab0a92"; + (node/*: any*/).hash = "6cfd2c9ec602ea2b50da57c845f4fcd4"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js index ff318d510293a..9e772e67a6f1d 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryNestedFragmentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<87125350c025233be8cc40c45714e271>> + * @generated SignedSource<<724839ac735cfc3ad120b88196bc7a5d>> * @flow * @lightSyntaxTransform * @nogrep @@ -354,7 +354,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "0fda8f3b3b888c596ad22c11ba6ecf03"; + (node/*: any*/).hash = "458b4f5da9c3a7ab5f8a37261fa8b23f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js index 747f3d6aaa44b..a688d1838ef19 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithLiteralArgsQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<54b7c0cb1f2a47a7d0ec1ff041181be0>> * @flow * @lightSyntaxTransform * @nogrep @@ -314,7 +314,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a7568b8997ebfad20088741629afcfa9"; + (node/*: any*/).hash = "896f2c0d23be1936f2c2371f29128ba2"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithStreamingQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithStreamingQuery.graphql.js index cef4549f3a6cc..33828f7dfc194 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithStreamingQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithStreamingQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<941eeee7d34fd9a5e5e59daa54cf25ee>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -342,7 +342,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "3804d84962fa5c729fa01498dc7e4224"; + (node/*: any*/).hash = "a8aa8fb48a0000532335af4b5e6f7573"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithoutIDQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithoutIDQuery.graphql.js index 5088d0cf0de3c..09582c38d33fe 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithoutIDQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePaginationFragmentTestUserQueryWithoutIDQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<90524f8256ace0bbd2885c59b00e59a2>> + * @generated SignedSource<<047f8a49a087d81653faf18ca849d217>> * @flow * @lightSyntaxTransform * @nogrep @@ -337,7 +337,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a2f6785e8ec3b4ea3f01ac2e5f4dc287"; + (node/*: any*/).hash = "13b0011aa8319dc4cdadad78cf6c67fe"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentRefetchQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentRefetchQuery.graphql.js index 446a48323bcaa..4df767a71168f 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentRefetchQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentRefetchQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<569024641be3b0efc2ca9e9f5b020b7e>> + * @generated SignedSource<<919069c963b6880374b876874c00ed31>> * @flow * @lightSyntaxTransform * @nogrep @@ -19,7 +19,7 @@ /*:: import type { ConcreteRequest, Query } from 'relay-runtime'; import type { FragmentType } from "relay-runtime"; -import type { usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType } from "./usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user.graphql"; +import type { usePrefetchableForwardPaginationFragmentTest_user$fragmentType } from "./usePrefetchableForwardPaginationFragmentTest_user.graphql"; export type usePrefetchableForwardPaginationFragmentRefetchQuery$variables = {| after?: ?string, before?: ?string, @@ -29,7 +29,7 @@ export type usePrefetchableForwardPaginationFragmentRefetchQuery$variables = {| |}; export type usePrefetchableForwardPaginationFragmentRefetchQuery$data = {| +node: ?{| - +$fragmentSpreads: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType, + +$fragmentSpreads: usePrefetchableForwardPaginationFragmentTest_user$fragmentType, |}, |}; export type usePrefetchableForwardPaginationFragmentRefetchQuery = {| @@ -131,7 +131,7 @@ return { { "args": null, "kind": "FragmentSpread", - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user" + "name": "usePrefetchableForwardPaginationFragmentTest_user" } ], "storageKey": null @@ -272,18 +272,18 @@ return { ] }, "params": { - "cacheID": "392f33f21d5b262df1a92d3547ae09bc", + "cacheID": "2f9567322cbafd63725e67eac1c69356", "id": null, "metadata": {}, "name": "usePrefetchableForwardPaginationFragmentRefetchQuery", "operationKind": "query", - "text": "query usePrefetchableForwardPaginationFragmentRefetchQuery(\n $after: ID\n $before: ID\n $first: Int\n $last: Int\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user\n id\n }\n}\n\nfragment usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user on User {\n friends(after: $after, first: $first, before: $before, last: $last) {\n edges {\n ...usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges on FriendsEdge {\n node {\n id\n name\n __typename\n }\n cursor\n}\n" + "text": "query usePrefetchableForwardPaginationFragmentRefetchQuery(\n $after: ID\n $before: ID\n $first: Int\n $last: Int\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...usePrefetchableForwardPaginationFragmentTest_user\n id\n }\n}\n\nfragment usePrefetchableForwardPaginationFragmentTest_user on User {\n friends(after: $after, first: $first, before: $before, last: $last) {\n edges {\n ...usePrefetchableForwardPaginationFragmentTest_user__edges\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment usePrefetchableForwardPaginationFragmentTest_user__edges on FriendsEdge {\n node {\n id\n name\n __typename\n }\n cursor\n}\n" } }; })(); if (__DEV__) { - (node/*: any*/).hash = "809455a8d7ada67cb84f3d111f6c6010"; + (node/*: any*/).hash = "b556c89ea274871519ed4779f197956d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTestQuery.graphql.js similarity index 75% rename from packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery.graphql.js rename to packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTestQuery.graphql.js index 21f05505b5df6..37a3629ff2598 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<8a5cc6645690b01d77261e637131b458>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -18,22 +18,22 @@ /*:: import type { ConcreteRequest, Query } from 'relay-runtime'; -import type { usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType } from "./usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user.graphql"; -export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery$variables = {| +import type { usePrefetchableForwardPaginationFragmentTest_user$fragmentType } from "./usePrefetchableForwardPaginationFragmentTest_user.graphql"; +export type usePrefetchableForwardPaginationFragmentTestQuery$variables = {| after?: ?string, before?: ?string, first?: ?number, id: string, last?: ?number, |}; -export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery$data = {| +export type usePrefetchableForwardPaginationFragmentTestQuery$data = {| +node: ?{| - +$fragmentSpreads: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType, + +$fragmentSpreads: usePrefetchableForwardPaginationFragmentTest_user$fragmentType, |}, |}; -export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery = {| - response: usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery$data, - variables: usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery$variables, +export type usePrefetchableForwardPaginationFragmentTestQuery = {| + response: usePrefetchableForwardPaginationFragmentTestQuery$data, + variables: usePrefetchableForwardPaginationFragmentTestQuery$variables, |}; */ @@ -117,7 +117,7 @@ return { ], "kind": "Fragment", "metadata": null, - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery", + "name": "usePrefetchableForwardPaginationFragmentTestQuery", "selections": [ { "alias": null, @@ -130,7 +130,7 @@ return { { "args": null, "kind": "FragmentSpread", - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user" + "name": "usePrefetchableForwardPaginationFragmentTest_user" } ], "storageKey": null @@ -149,7 +149,7 @@ return { (v4/*: any*/) ], "kind": "Operation", - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery", + "name": "usePrefetchableForwardPaginationFragmentTestQuery", "selections": [ { "alias": null, @@ -271,21 +271,21 @@ return { ] }, "params": { - "cacheID": "6cd62bc50d478e401286fbd253466497", + "cacheID": "9e9b011d9b52d31f16e8e2ee376822bb", "id": null, "metadata": {}, - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery", + "name": "usePrefetchableForwardPaginationFragmentTestQuery", "operationKind": "query", - "text": "query usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery(\n $id: ID!\n $after: ID\n $first: Int\n $before: ID\n $last: Int\n) {\n node(id: $id) {\n __typename\n ...usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user\n id\n }\n}\n\nfragment usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user on User {\n friends(after: $after, first: $first, before: $before, last: $last) {\n edges {\n ...usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges on FriendsEdge {\n node {\n id\n name\n __typename\n }\n cursor\n}\n" + "text": "query usePrefetchableForwardPaginationFragmentTestQuery(\n $id: ID!\n $after: ID\n $first: Int\n $before: ID\n $last: Int\n) {\n node(id: $id) {\n __typename\n ...usePrefetchableForwardPaginationFragmentTest_user\n id\n }\n}\n\nfragment usePrefetchableForwardPaginationFragmentTest_user on User {\n friends(after: $after, first: $first, before: $before, last: $last) {\n edges {\n ...usePrefetchableForwardPaginationFragmentTest_user__edges\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment usePrefetchableForwardPaginationFragmentTest_user__edges on FriendsEdge {\n node {\n id\n name\n __typename\n }\n cursor\n}\n" } }; })(); if (__DEV__) { - (node/*: any*/).hash = "48bd7cb20fb4977c3582b839ce846c1f"; + (node/*: any*/).hash = "785e649312a81a6861dbabc7c8c80d56"; } module.exports = ((node/*: any*/)/*: Query< - usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery$variables, - usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery$data, + usePrefetchableForwardPaginationFragmentTestQuery$variables, + usePrefetchableForwardPaginationFragmentTestQuery$data, >*/); diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTest_user.graphql.js similarity index 74% rename from packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user.graphql.js rename to packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTest_user.graphql.js index 20eadaa490dfd..2e5388f8e08dc 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTest_user.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<369c689b8624b2aa4e3cea4ad88d864a>> + * @generated SignedSource<<8becc1a8ce7b77e8e0c4d71b66d7450f>> * @flow * @lightSyntaxTransform * @nogrep @@ -18,15 +18,15 @@ /*:: import type { ReaderFragment, PrefetchableRefetchableFragment } from 'relay-runtime'; -import type { usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$fragmentType } from "./usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges.graphql"; +import type { usePrefetchableForwardPaginationFragmentTest_user__edges$fragmentType } from "./usePrefetchableForwardPaginationFragmentTest_user__edges.graphql"; import type { FragmentType } from "relay-runtime"; -declare export opaque type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType: FragmentType; +declare export opaque type usePrefetchableForwardPaginationFragmentTest_user$fragmentType: FragmentType; type usePrefetchableForwardPaginationFragmentRefetchQuery$variables = any; -type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$data = any; -export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$data = {| +type usePrefetchableForwardPaginationFragmentTest_user__edges$data = any; +export type usePrefetchableForwardPaginationFragmentTest_user$data = {| +friends: ?{| +edges: ?$ReadOnlyArray, +pageInfo: ?{| +endCursor: ?string, @@ -36,11 +36,11 @@ export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$data = |}, |}, +id: string, - +$fragmentType: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType, + +$fragmentType: usePrefetchableForwardPaginationFragmentTest_user$fragmentType, |}; -export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$key = { - +$data?: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$data, - +$fragmentSpreads: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType, +export type usePrefetchableForwardPaginationFragmentTest_user$key = { + +$data?: usePrefetchableForwardPaginationFragmentTest_user$data, + +$fragmentSpreads: usePrefetchableForwardPaginationFragmentTest_user$fragmentType, ... }; */ @@ -98,10 +98,10 @@ return { "identifierField": "id", "identifierQueryVariableName": "id" }, - "edgesFragment": require('./usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges.graphql') + "edgesFragment": require('./usePrefetchableForwardPaginationFragmentTest_user__edges.graphql') } }, - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user", + "name": "usePrefetchableForwardPaginationFragmentTest_user", "selections": [ { "alias": "friends", @@ -122,7 +122,7 @@ return { { "args": null, "kind": "FragmentSpread", - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges" + "name": "usePrefetchableForwardPaginationFragmentTest_user__edges" } ], "storageKey": null @@ -183,12 +183,12 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "809455a8d7ada67cb84f3d111f6c6010"; + (node/*: any*/).hash = "b556c89ea274871519ed4779f197956d"; } module.exports = ((node/*: any*/)/*: PrefetchableRefetchableFragment< - usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$fragmentType, - usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$data, - usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$data, + usePrefetchableForwardPaginationFragmentTest_user$fragmentType, + usePrefetchableForwardPaginationFragmentTest_user$data, + usePrefetchableForwardPaginationFragmentTest_user__edges$data, usePrefetchableForwardPaginationFragmentRefetchQuery$variables, >*/); diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTest_user__edges.graphql.js similarity index 65% rename from packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges.graphql.js rename to packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTest_user__edges.graphql.js index 1ebdea9b752da..741fcda827535 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePrefetchableForwardPaginationFragmentTest_user__edges.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -19,19 +19,19 @@ /*:: import type { Fragment, ReaderFragment } from 'relay-runtime'; import type { FragmentType } from "relay-runtime"; -declare export opaque type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$fragmentType: FragmentType; -export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$data = $ReadOnlyArray<{| +declare export opaque type usePrefetchableForwardPaginationFragmentTest_user__edges$fragmentType: FragmentType; +export type usePrefetchableForwardPaginationFragmentTest_user__edges$data = $ReadOnlyArray<{| +cursor: ?string, +node: ?{| +__typename: "User", +id: string, +name: ?string, |}, - +$fragmentType: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$fragmentType, + +$fragmentType: usePrefetchableForwardPaginationFragmentTest_user__edges$fragmentType, |}>; -export type usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$key = $ReadOnlyArray<{ - +$data?: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$data, - +$fragmentSpreads: usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$fragmentType, +export type usePrefetchableForwardPaginationFragmentTest_user__edges$key = $ReadOnlyArray<{ + +$data?: usePrefetchableForwardPaginationFragmentTest_user__edges$data, + +$fragmentSpreads: usePrefetchableForwardPaginationFragmentTest_user__edges$fragmentType, ... }>; */ @@ -42,7 +42,7 @@ var node/*: ReaderFragment*/ = { "metadata": { "plural": true }, - "name": "usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges", + "name": "usePrefetchableForwardPaginationFragmentTest_user__edges", "selections": [ { "alias": null, @@ -89,6 +89,6 @@ var node/*: ReaderFragment*/ = { }; module.exports = ((node/*: any*/)/*: Fragment< - usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$fragmentType, - usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user__edges$data, + usePrefetchableForwardPaginationFragmentTest_user__edges$fragmentType, + usePrefetchableForwardPaginationFragmentTest_user__edges$data, >*/); diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_Query.graphql.js index 9d2d1501ed299..98f52c67357f8 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<1bd7619ea2f07d3500636a825112fa19>> + * @generated SignedSource<<6ebffb7ce1854ae653cee7bbf1eea34a>> * @flow * @lightSyntaxTransform * @nogrep @@ -213,7 +213,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "57f29c979bd1ac2b46b7841b521d1cb2"; + (node/*: any*/).hash = "0d2bf5e56b0727c897800a81971dc7db"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_badQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_badQuery.graphql.js index 3aae2d82cff4d..7d5f24c33eaba 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_badQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryProvidedVariablesTest_badQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<940e03983e6e001ebaf61ce67f5941e5>> + * @generated SignedSource<<4aeea8ffd974da26d3d161cf97b903a6>> * @flow * @lightSyntaxTransform * @nogrep @@ -168,7 +168,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "38101eec78c6bee2608fbe821589dd15"; + (node/*: any*/).hash = "9f08a83ca6f077bedba106cc1674156d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestDeferQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestDeferQuery.graphql.js index 45dbbdb021a6a..ca4bdc89ca243 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestDeferQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestDeferQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<6f689958c3f5e6e047263cd944af4020>> * @flow * @lightSyntaxTransform * @nogrep @@ -159,7 +159,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "6338c0f9d862dcd893716ffc9df2e626"; + (node/*: any*/).hash = "4b7abb047aa04c8ea7c19b5ab39e46ed"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestQuery.graphql.js index 995a602bd721c..7934b567ecce8 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/usePreloadedQueryReactDoubleEffectsTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<567baaa0c209320f3f5e49f65363a923>> * @flow * @lightSyntaxTransform * @nogrep @@ -147,7 +147,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "0bbeeb14ab9e57bc7a6ae0d7486fcb9a"; + (node/*: any*/).hash = "5f8dbf688a5b0fad6793fda136b755ff"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useQueryLoaderReactDoubleEffectsTestQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useQueryLoaderReactDoubleEffectsTestQuery.graphql.js index 8b0b3d80fee07..4ce470bccdf77 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useQueryLoaderReactDoubleEffectsTestQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useQueryLoaderReactDoubleEffectsTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<4b7f18186ac1d4d6dae15e49aac6cc48>> + * @generated SignedSource<<10ff4ef6ce88bc1ebd070a07e4838553>> * @flow * @lightSyntaxTransform * @nogrep @@ -133,7 +133,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "813ed6f6be85c7ddc56659a2312f6190"; + (node/*: any*/).hash = "0a90fca296d573765285d246538d5929"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Fragment.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Fragment.graphql.js index 15d027a463743..939c0efdfde55 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Fragment.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Fragment.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<7c2c05ec0d836f9fab77060b8dc4447e>> + * @generated SignedSource<<074e7dac8c97944de8b6ce60fd1eb626>> * @flow * @lightSyntaxTransform * @nogrep @@ -22,7 +22,6 @@ import type { FragmentType } from "relay-runtime"; declare export opaque type useRefetchableFragmentNodeTest1Fragment$fragmentType: FragmentType; type useRefetchableFragmentNodeTest1FragmentRefetchQuery$variables = any; export type useRefetchableFragmentNodeTest1Fragment$data = {| - +__token: string, +actor: ?{| +name: ?string, |}, @@ -78,13 +77,6 @@ var node/*: ReaderFragment*/ = { "kind": "ScalarField", "name": "fetch_id", "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null } ], "type": "NonNodeStory", diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1FragmentRefetchQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1FragmentRefetchQuery.graphql.js index 40f48a2d39d41..86c6f8a266a60 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1FragmentRefetchQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1FragmentRefetchQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -130,13 +130,6 @@ return { "name": "fetch_id", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null - }, (v2/*: any*/) ], "storageKey": null @@ -144,12 +137,12 @@ return { ] }, "params": { - "cacheID": "f90df4dc16ad217f9e91605e41c7bebe", + "cacheID": "3129a94c4b427c07b464a3e4b9f27849", "id": null, "metadata": {}, "name": "useRefetchableFragmentNodeTest1FragmentRefetchQuery", "operationKind": "query", - "text": "query useRefetchableFragmentNodeTest1FragmentRefetchQuery(\n $id: ID!\n) {\n fetch__NonNodeStory(input_fetch_id: $id) {\n ...useRefetchableFragmentNodeTest1Fragment\n id\n }\n}\n\nfragment useRefetchableFragmentNodeTest1Fragment on NonNodeStory {\n actor {\n __typename\n name\n id\n }\n fetch_id\n __token\n}\n" + "text": "query useRefetchableFragmentNodeTest1FragmentRefetchQuery(\n $id: ID!\n) {\n fetch__NonNodeStory(input_fetch_id: $id) {\n ...useRefetchableFragmentNodeTest1Fragment\n id\n }\n}\n\nfragment useRefetchableFragmentNodeTest1Fragment on NonNodeStory {\n actor {\n __typename\n name\n id\n }\n fetch_id\n}\n" } }; })(); diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Query.graphql.js index aa19f418355bb..fc7ac95f8cf60 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<10e1a861ea49f1a624859dad7a53c95a>> + * @generated SignedSource<<2319a3d7450db8fb50d547d5a91ab33b>> * @flow * @lightSyntaxTransform * @nogrep @@ -129,13 +129,6 @@ return { "name": "fetch_id", "storageKey": null }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "__token", - "storageKey": null - }, (v2/*: any*/) ], "storageKey": null @@ -143,12 +136,12 @@ return { ] }, "params": { - "cacheID": "48452883758b52f03c316637a58a7bf9", + "cacheID": "2b1fe038fd3a80f4e81b56e3b864e547", "id": null, "metadata": {}, "name": "useRefetchableFragmentNodeTest1Query", "operationKind": "query", - "text": "query useRefetchableFragmentNodeTest1Query(\n $id: ID!\n) {\n nonNodeStory(id: $id) {\n ...useRefetchableFragmentNodeTest1Fragment\n id\n }\n}\n\nfragment useRefetchableFragmentNodeTest1Fragment on NonNodeStory {\n actor {\n __typename\n name\n id\n }\n fetch_id\n __token\n}\n" + "text": "query useRefetchableFragmentNodeTest1Query(\n $id: ID!\n) {\n nonNodeStory(id: $id) {\n ...useRefetchableFragmentNodeTest1Fragment\n id\n }\n}\n\nfragment useRefetchableFragmentNodeTest1Fragment on NonNodeStory {\n actor {\n __typename\n name\n id\n }\n fetch_id\n}\n" } }; })(); diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest2Query.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest2Query.graphql.js index 18fa4646f72fa..36cbdc52af8a6 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest2Query.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTest2Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<4b933e9d55257062892abd615f86047f>> + * @generated SignedSource<<7478944cd3dbb6602b6bb6cc55549dd1>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "cbfab6b35baf272e1919c50195df62d0"; + (node/*: any*/).hash = "c6d3e08c02e35bb5a19b2b9736e4fc14"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQuery.graphql.js index f4d39c2d286a3..90e5d73f4bd28 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<2c8119f78dc84414a2c2e3af3236b73b>> + * @generated SignedSource<<2d1f5eda44b115c1fbb3851e34cc1dbd>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "94c9abdfb85ce932e3a33edc6295e643"; + (node/*: any*/).hash = "57abea6eac29136d88830ce479f8e64d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryNestedFragmentQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryNestedFragmentQuery.graphql.js index 4edb91650378e..9a813bd94ae89 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryNestedFragmentQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryNestedFragmentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<732c507971e2825b8ea30317c5e1b280>> + * @generated SignedSource<<9845e8eed54c5f1856ba893ec688f537>> * @flow * @lightSyntaxTransform * @nogrep @@ -199,7 +199,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "845c776ed52ad25feb496e052f8f65cb"; + (node/*: any*/).hash = "7ca81283026cd4a1b1204958f00d095c"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithArgsQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithArgsQuery.graphql.js index 45c552f48ee55..0218315156e29 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithArgsQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithArgsQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -177,7 +177,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "eb3a8dd67a24e472e2e18e80041d344a"; + (node/*: any*/).hash = "f21abe6662fcea801ab93fb27b9844cc"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithLiteralArgsQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithLiteralArgsQuery.graphql.js index 89c4e97e8c773..f88eff517a29c 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithLiteralArgsQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeTestUserQueryWithLiteralArgsQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<1d8ee696790736246cd73800b1252ada>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "09f9c5bc18c5bfc0ded57db2a09602a9"; + (node/*: any*/).hash = "419541101379d9a2ca9bebc22e817493"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeWithSuspenseTransitionTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeWithSuspenseTransitionTestUserQuery.graphql.js index 3f45da91d0d10..858f0543af7f5 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeWithSuspenseTransitionTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentNodeWithSuspenseTransitionTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<044e975f172acb4522f2ed35a1bab818>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "7dd300784a6642a4b84870d9abd398b9"; + (node/*: any*/).hash = "293f9ed14d99bd4ecc3eb91ad23351a2"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentTestUserQuery.graphql.js b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentTestUserQuery.graphql.js index de3bcba6b54f5..8d422db515ba6 100644 --- a/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentTestUserQuery.graphql.js +++ b/packages/react-relay/relay-hooks/__tests__/__generated__/useRefetchableFragmentTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<8171e4f68cc25d20cf2cc29ef7ad3c56>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "4420905b52cf335b2645d133241e269a"; + (node/*: any*/).hash = "d3ff1134ddf6dda8f4cc0ce4d009f6f8"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js b/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js index 9e8b9b05acaed..a83f8e43c22d1 100644 --- a/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js +++ b/packages/react-relay/relay-hooks/__tests__/loadQuery-test.js @@ -18,6 +18,7 @@ import type { } from './__generated__/loadQueryTestQuery.graphql'; import type { CacheConfig, + INetwork, LogRequestInfoFunction, Query, RequestParameters, @@ -96,6 +97,7 @@ describe('loadQuery', () => { let mockAvailability: {fetchTime?: number, status: string}; let disposeOnloadCallback; let executeOnloadCallback; + let checkOperation; beforeEach(() => { fetch = jest.fn( @@ -122,7 +124,17 @@ describe('loadQuery', () => { return observable; }, ); - environment = createMockEnvironment({network: Network.create(fetch)}); + function wrapNetworkExecute(network: INetwork): INetwork { + return { + execute: (_1, _2, _3, _4, _5, _6, _7, _checkOperation) => { + checkOperation = _checkOperation; + return network.execute(_1, _2, _3, _4, _5, _6, _7, _checkOperation); + }, + }; + } + environment = createMockEnvironment({ + network: wrapNetworkExecute(Network.create(fetch)), + }); jest.clearAllTimers(); jest.useFakeTimers(); @@ -397,6 +409,48 @@ describe('loadQuery', () => { expect(disposeEnvironmentRetain).toHaveBeenCalledTimes(1); }); }); + + describe("with fetchPolicy === 'store-and-network'", () => { + it('should call fetch if the query can be fulfilled by the store', () => { + const {source} = loadQuery( + environment, + preloadableConcreteRequest, + variables, + { + fetchPolicy: 'store-and-network', + }, + ); + expect(fetch).toHaveBeenCalled(); + // $FlowFixMe[method-unbinding] added when improving typing for this parameters + expect(environment.executeWithSource).toHaveBeenCalled(); + expect(source).toBeDefined(); + // Query should still be retained even if we don't fetch + // $FlowFixMe[method-unbinding] added when improving typing for this parameters + expect(environment.retain).toHaveBeenCalled(); + }); + + it('returns the correct operation availability (available)', () => { + loadQuery(environment, preloadableConcreteRequest, variables, { + fetchPolicy: 'store-and-network', + }); + expect(fetch).toHaveBeenCalled(); + expect(checkOperation != null && checkOperation().status).toEqual( + 'available', + ); + }); + + it('returns the correct operation availability (missing)', () => { + mockAvailability = {status: 'missing'}; + + loadQuery(environment, preloadableConcreteRequest, variables, { + fetchPolicy: 'store-and-network', + }); + expect(fetch).toHaveBeenCalled(); + expect(checkOperation != null && checkOperation().status).toEqual( + 'missing', + ); + }); + }); }); describe('when the query AST is unavailable synchronously', () => { diff --git a/packages/react-relay/relay-hooks/__tests__/preloadQuery_DEPRECATED-test.js b/packages/react-relay/relay-hooks/__tests__/preloadQuery_DEPRECATED-test.js index c68aae7492a8f..5af0af0822c68 100644 --- a/packages/react-relay/relay-hooks/__tests__/preloadQuery_DEPRECATED-test.js +++ b/packages/react-relay/relay-hooks/__tests__/preloadQuery_DEPRECATED-test.js @@ -11,7 +11,10 @@ 'use strict'; -import type {GraphQLResponse} from 'relay-runtime/network/RelayNetworkTypes'; +import type { + GraphQLResponse, + INetwork, +} from 'relay-runtime/network/RelayNetworkTypes'; const preloadQuery_DEPRECATED = require('../preloadQuery_DEPRECATED'); const { @@ -49,7 +52,7 @@ const query = graphql` query.params.id = '12345'; const params = { - kind: 'PreloadableConcreteRequest', + kind: 'PreloadableConcreteRequest' as const, params: query.params, }; @@ -76,19 +79,37 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( let sink; let variables; let operation; + let checkOperation; beforeEach(() => { // $FlowFixMe[missing-local-annot] error found when enabling Flow LTI mode - fetch = jest.fn((_query, _variables, _cacheConfig) => { + fetch = jest.fn((_query, _variables, _cacheConfig, _4, _5) => { // $FlowFixMe[missing-local-annot] error found when enabling Flow LTI mode return Observable.create(_sink => { sink = _sink; }); }); - + function wrapNetworkExecute(network: INetwork): INetwork { + return { + execute: (_1, _2, _3, _4, _5, _6, _7, _checkOperation) => { + checkOperation = _checkOperation; + return network.execute( + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _checkOperation, + ); + }, + }; + } const multiActorEnvironment = new MultiActorEnvironment({ // $FlowFixMe[invalid-tuple-arity] Error found while enabling LTI on this file - createNetworkForActor: _actorID => Network.create(fetch), + createNetworkForActor: _actorID => + wrapNetworkExecute(Network.create(fetch)), createStoreForActor: _actorID => new Store(new RecordSource(), { gcReleaseBufferSize: 1, @@ -99,7 +120,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( ? multiActorEnvironment.forActor(getActorIdentifier('actor:1234')) : new Environment({ // $FlowFixMe[invalid-tuple-arity] Error found while enabling LTI on this file - network: Network.create(fetch), + network: wrapNetworkExecute(Network.create(fetch)), store: new Store(new RecordSource(), { gcReleaseBufferSize: 1, }), @@ -535,6 +556,10 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( expect(fetch.mock.calls[0][0]).toBe(query.params); expect(fetch.mock.calls[0][1]).toEqual(variables); expect(fetch.mock.calls[0][2]).toEqual({force: true}); + expect(checkOperation && checkOperation()).toEqual({ + status: 'available', + fetchTime, + }); const [events, observer] = createObserver(); if (preloaded.source) { @@ -906,6 +931,7 @@ describe('Preload queries that use provided variables', () => { query preloadQueryDEPRECATEDTest_ProvidedVarQuery($id: ID!) { node(id: $id) { ...preloadQueryDEPRECATEDTest_ProvidedVarFragment + @dangerously_unaliased_fixme } } `; @@ -924,7 +950,7 @@ describe('Preload queries that use provided variables', () => { queryWithProvidedVar.params.id = '12346'; const paramsWithProvidedVar = { - kind: 'PreloadableConcreteRequest', + kind: 'PreloadableConcreteRequest' as const, params: queryWithProvidedVar.params, }; diff --git a/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-test.js b/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-test.js index 5a339424d212f..57a779bc0af15 100644 --- a/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-test.js @@ -204,6 +204,7 @@ describe('useBlockingPaginationFragment', () => { ) { node(id: $id) { ...useBlockingPaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby) } } @@ -221,6 +222,7 @@ describe('useBlockingPaginationFragment', () => { node(id: $id) { actor { ...useBlockingPaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments( isViewerFriendLocal: $isViewerFriend orderby: $orderby @@ -242,6 +244,7 @@ describe('useBlockingPaginationFragment', () => { viewer { actor { ...useBlockingPaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments( isViewerFriendLocal: $isViewerFriend orderby: $orderby @@ -260,6 +263,7 @@ describe('useBlockingPaginationFragment', () => { ) { node(id: $id) { ...useBlockingPaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: true, orderby: ["name"]) } } diff --git a/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js b/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js index 06b250155f909..6aa79140a6be2 100644 --- a/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useBlockingPaginationFragment-with-suspense-transition-test.js @@ -267,6 +267,7 @@ describe('useBlockingPaginationFragment with useTransition', () => { node(id: $id) { actor { ...useBlockingPaginationFragmentWithSuspenseTransitionTestUserFragment + @dangerously_unaliased_fixme @arguments( isViewerFriendLocal: $isViewerFriend orderby: $orderby @@ -288,6 +289,7 @@ describe('useBlockingPaginationFragment with useTransition', () => { viewer { actor { ...useBlockingPaginationFragmentWithSuspenseTransitionTestUserFragment + @dangerously_unaliased_fixme @arguments( isViewerFriendLocal: $isViewerFriend orderby: $orderby diff --git a/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-react-double-effects-test.js b/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-react-double-effects-test.js index e7eca9ef52cfb..49fd4a947b4ba 100644 --- a/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-react-double-effects-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-react-double-effects-test.js @@ -37,6 +37,8 @@ function expectToHaveFetched( liveConfigId?: ?string, metadata?: {[key: string]: mixed}, onSubscribe?: () => void, + onResume?: (pauseTimeMs: number) => void, + onPause?: (mqttConnectionIsOk: boolean, internetIsOk: boolean) => void, poll?: ?number, transactionId?: ?string, }, @@ -133,6 +135,7 @@ describe.skip('useEntryPointLoader-react-double-effects', () => { id name ...useEntryPointLoaderReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-test.js b/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-test.js index 9475758036215..2a8ef52e2bfe8 100644 --- a/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useEntryPointLoader-test.js @@ -210,7 +210,7 @@ it('does not dispose the entry point before the new component tree unsuspends in let transitionToSecondRoute; function ConcurrentWrapper() { - const [route, setRoute] = React.useState('FIRST'); + const [route, setRoute] = React.useState<'FIRST' | 'SECOND'>('FIRST'); transitionToSecondRoute = () => React.startTransition(() => setRoute('SECOND')); @@ -558,6 +558,7 @@ it('disposes all entry points if the callback is called, the component suspends, entryPointLoaderCallback({}); }); const secondDispose = dispose; + // $FlowFixMe[incompatible-use] expect(outerInstance.toJSON()).toEqual('fallback'); // TODO(T19754110): This fails in OSS where we have concurrent mode, but might @@ -609,6 +610,7 @@ it('disposes all entry points if the component suspends, another entry point is // *even though the component is in a suspended state.* As such, it commits and // the entry point is disposed. expect(renderCount).toBeLessThanOrEqual(2); + // $FlowFixMe[incompatible-use] expect(outerInstance.toJSON()).toEqual('fallback'); expect(dispose).not.toHaveBeenCalled(); ReactTestRenderer.act(() => outerInstance.unmount()); diff --git a/packages/react-relay/relay-hooks/__tests__/useFragment-WithOperationTrackerSuspense-test.js b/packages/react-relay/relay-hooks/__tests__/useFragment-WithOperationTrackerSuspense-test.js index e1d87e119a315..44f83167cc909 100644 --- a/packages/react-relay/relay-hooks/__tests__/useFragment-WithOperationTrackerSuspense-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useFragment-WithOperationTrackerSuspense-test.js @@ -66,6 +66,7 @@ describe('useFragment with Operation Tracker and Suspense behavior', () => { node(id: $id) { __typename ...useFragmentWithOperationTrackerSuspenseTestFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useFragment-test.js b/packages/react-relay/relay-hooks/__tests__/useFragment-test.js index 1975bf388273a..7cda19939c376 100644 --- a/packages/react-relay/relay-hooks/__tests__/useFragment-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useFragment-test.js @@ -7,6 +7,7 @@ * @flow * @format * @oncall relay + * @jest-environment jsdom */ 'use strict'; @@ -23,9 +24,9 @@ import type {OperationDescriptor} from 'relay-runtime/store/RelayStoreTypes'; import type {Fragment} from 'relay-runtime/util/RelayRuntimeTypes'; const useFragmentImpl = require('../useFragment'); +const ReactTestingLibrary = require('@testing-library/react'); const React = require('react'); const ReactRelayContext = require('react-relay/ReactRelayContext'); -const TestRenderer = require('react-test-renderer'); const { FRAGMENT_OWNER_KEY, FRAGMENTS_KEY, @@ -33,6 +34,7 @@ const { createOperationDescriptor, graphql, } = require('relay-runtime'); +const RelayFeatureFlags = require('relay-runtime/util/RelayFeatureFlags'); const {createMockEnvironment} = require('relay-test-utils'); const { disallowConsoleErrors, @@ -57,6 +59,7 @@ let renderSpy; let SingularRenderer; let PluralRenderer; let ContextProvider; +let setEnvironment; hook useFragment( fragmentNode: @@ -79,7 +82,6 @@ hook useFragment( function assertFragmentResults(expected: any) { // This ensures that useEffect runs jest.runAllImmediates(); - expect(renderSpy).toBeCalledTimes(1); const actualData = renderSpy.mock.calls[0][0]; expect(actualData).toEqual(expected); renderSpy.mockClear(); @@ -95,260 +97,314 @@ function createFragmentRef(id: string, owner: OperationDescriptor) { }; } -beforeEach(() => { - renderSpy = jest.fn< - [useFragmentTestUserFragment$data | useFragmentTestUsersFragment$data], - mixed, - >(); +describe.each([ + ['Experimental', true], + ['Current', false], +])( + 'useFragment (%s)', + (name, ENABLE_ACTIVITY_COMPATIBILITY, ENABLE_RESOURCE_EFFECTS) => { + beforeEach(() => { + RelayFeatureFlags.ENABLE_ACTIVITY_COMPATIBILITY = + ENABLE_ACTIVITY_COMPATIBILITY; - // Set up environment and base data - environment = createMockEnvironment(); - graphql` - fragment useFragmentTestNestedUserFragment on User { - username - } - `; - singularVariables = {id: '1'}; - pluralVariables = {ids: ['1', '2']}; - gqlSingularQuery = graphql` - query useFragmentTestUserQuery($id: ID!) { - node(id: $id) { - ...useFragmentTestUserFragment - } - } - `; - gqlSingularFragment = graphql` - fragment useFragmentTestUserFragment on User { - id - name - ...useFragmentTestNestedUserFragment - } - `; - gqlPluralQuery = graphql` - query useFragmentTestUsersQuery($ids: [ID!]!) { - nodes(ids: $ids) { - ...useFragmentTestUsersFragment - } - } - `; - gqlPluralFragment = graphql` - fragment useFragmentTestUsersFragment on User @relay(plural: true) { - id - name - ...useFragmentTestNestedUserFragment - } - `; - singularQuery = createOperationDescriptor( - gqlSingularQuery, - singularVariables, - ); - pluralQuery = createOperationDescriptor(gqlPluralQuery, pluralVariables); - environment.commitPayload(singularQuery, { - node: { - __typename: 'User', - id: '1', - name: 'Alice', - username: 'useralice', - }, - }); - environment.commitPayload(pluralQuery, { - nodes: [ - { - __typename: 'User', - id: '1', - name: 'Alice', - username: 'useralice', - profile_picture: null, - }, - { - __typename: 'User', - id: '2', - name: 'Bob', - username: 'userbob', - profile_picture: null, - }, - ], - }); + renderSpy = jest.fn< + [useFragmentTestUserFragment$data | useFragmentTestUsersFragment$data], + mixed, + >(); - // Set up renderers - SingularRenderer = (props: { - user: ?( - | useFragmentTestUserFragment$data - | useFragmentTestUsersFragment$data - ), - }) => null; - PluralRenderer = (props: { - users: ?( - | useFragmentTestUserFragment$data - | useFragmentTestUsersFragment$data - ), - }) => null; - const SingularContainer = (props: { - userRef?: {$data?: {...}, ...}, - owner: $FlowFixMe, - ... - }) => { - // We need a render a component to run a Hook - const owner = props.owner; - const userRef = props.hasOwnProperty('userRef') - ? props.userRef - : { - [ID_KEY]: owner.request.variables.id, - [FRAGMENTS_KEY]: { - useFragmentTestUserFragment: {}, + // Set up environment and base data + environment = createMockEnvironment(); + graphql` + fragment useFragmentTestNestedUserFragment on User { + username + } + `; + singularVariables = {id: '1'}; + pluralVariables = {ids: ['1', '2']}; + gqlSingularQuery = graphql` + query useFragmentTestUserQuery($id: ID!) { + node(id: $id) { + ...useFragmentTestUserFragment @dangerously_unaliased_fixme + } + } + `; + gqlSingularFragment = graphql` + fragment useFragmentTestUserFragment on User { + id + name + ...useFragmentTestNestedUserFragment + } + `; + gqlPluralQuery = graphql` + query useFragmentTestUsersQuery($ids: [ID!]!) { + nodes(ids: $ids) { + ...useFragmentTestUsersFragment + } + } + `; + gqlPluralFragment = graphql` + fragment useFragmentTestUsersFragment on User @relay(plural: true) { + id + name + ...useFragmentTestNestedUserFragment + } + `; + singularQuery = createOperationDescriptor( + gqlSingularQuery, + singularVariables, + ); + pluralQuery = createOperationDescriptor(gqlPluralQuery, pluralVariables); + environment.commitPayload(singularQuery, { + node: { + __typename: 'User', + id: '1', + name: 'Alice', + username: 'useralice', + }, + }); + environment.commitPayload(pluralQuery, { + nodes: [ + { + __typename: 'User', + id: '1', + name: 'Alice', + username: 'useralice', + profile_picture: null, }, - [FRAGMENT_OWNER_KEY]: owner.request, - }; - const userData = useFragment(gqlSingularFragment, userRef); - return ; - }; - - const PluralContainer = (props: { - usersRef?: $ReadOnlyArray<{$data?: {...}, ...}>, - owner: $FlowFixMe, - ... - }) => { - const owner = props.owner; - const usersRef = props.hasOwnProperty('usersRef') - ? props.usersRef - : owner.request.variables.ids.map(id => ({ - [ID_KEY]: id, - [FRAGMENTS_KEY]: { - useFragmentTestUsersFragment: {}, + { + __typename: 'User', + id: '2', + name: 'Bob', + username: 'userbob', + profile_picture: null, }, - [FRAGMENT_OWNER_KEY]: owner.request, - })); + ], + }); - const usersData = useFragment(gqlPluralFragment, usersRef); - return ; - }; + // Set up renderers + SingularRenderer = (props: { + user: ?( + | useFragmentTestUserFragment$data + | useFragmentTestUsersFragment$data + ), + }) => null; + PluralRenderer = (props: { + users: ?( + | useFragmentTestUserFragment$data + | useFragmentTestUsersFragment$data + ), + }) => null; + const SingularContainer = (props: { + userRef?: {$data?: {...}, ...}, + owner: $FlowFixMe, + ... + }) => { + // We need a render a component to run a Hook + const owner = props.owner; + const userRef = props.hasOwnProperty('userRef') + ? props.userRef + : { + [ID_KEY]: owner.request.variables.id, + [FRAGMENTS_KEY]: { + useFragmentTestUserFragment: {}, + }, + [FRAGMENT_OWNER_KEY]: owner.request, + }; + const userData = useFragment(gqlSingularFragment, userRef); + return ; + }; - const relayContext = {environment}; - ContextProvider = ({children}: {children: React.Node}) => { - return ( - - {children} - - ); - }; + const PluralContainer = (props: { + usersRef?: $ReadOnlyArray<{$data?: {...}, ...}>, + owner: $FlowFixMe, + ... + }) => { + const owner = props.owner; + const usersRef = props.hasOwnProperty('usersRef') + ? props.usersRef + : owner.request.variables.ids.map(id => ({ + [ID_KEY]: id, + [FRAGMENTS_KEY]: { + useFragmentTestUsersFragment: {}, + }, + [FRAGMENT_OWNER_KEY]: owner.request, + })); - renderSingularFragment = ( - props?: { - owner?: $FlowFixMe, - userRef?: $FlowFixMe, - ... - }, - existing: $FlowFixMe, - ) => { - const elements = ( - - - - - - ); - let ret; - TestRenderer.act(() => { - if (existing) { - existing.update(elements); - ret = existing; - } else { - ret = TestRenderer.create(elements); - } + const usersData = useFragment(gqlPluralFragment, usersRef); + return ; + }; + + ContextProvider = ({children}: {children: React.Node}) => { + // $FlowFixMe[react-rule-hook] + const [env, _setEnv] = React.useState(environment); + // $FlowFixMe[react-rule-hook] + const relayContext = React.useMemo(() => ({environment: env}), [env]); + + setEnvironment = _setEnv; + return ( + + {children} + + ); + }; + + renderSingularFragment = ( + props?: { + owner?: $FlowFixMe, + userRef?: $FlowFixMe, + ... + }, + rerender: $FlowFixMe, + ) => { + const elements = ( + + + + + + ); + if (rerender) { + return rerender(elements); + } else { + return ReactTestingLibrary.render(elements); + } + }; + + renderPluralFragment = ( + props?: { + owner?: $FlowFixMe, + userRef?: $FlowFixMe, + ... + }, + rerender: $FlowFixMe, + ) => { + const elements = ( + + + + + + ); + if (rerender) { + return rerender(elements); + } else { + return ReactTestingLibrary.render(elements); + } + }; }); - return ret; - }; - renderPluralFragment = ( - props?: { - owner?: $FlowFixMe, - userRef?: $FlowFixMe, - ... - }, - existing: $FlowFixMe, - ) => { - const elements = ( - - - - - - ); - let ret; - TestRenderer.act(() => { - if (existing) { - existing.update(elements); - ret = existing; - } else { - ret = TestRenderer.create(elements); - } + afterEach(() => { + environment.mockClear(); + renderSpy.mockClear(); + RelayFeatureFlags.ENABLE_ACTIVITY_COMPATIBILITY = false; }); - return ret; - }; -}); -afterEach(() => { - environment.mockClear(); - renderSpy.mockClear(); -}); + it('handles environnment changes', () => { + renderSingularFragment(); + assertFragmentResults({ + id: '1', + name: 'Alice', + ...createFragmentRef('1', singularQuery), + }); -it('should render singular fragment without error when data is available', () => { - renderSingularFragment(); - assertFragmentResults({ - id: '1', - name: 'Alice', - ...createFragmentRef('1', singularQuery), - }); -}); + const newEnvironment = createMockEnvironment(); + newEnvironment.commitPayload(singularQuery, { + node: { + __typename: 'User', + id: '1', + name: 'Alice in a different env', + username: null, + }, + }); -it('should return the same data object if rendered multiple times: singular fragment', () => { - const container = renderSingularFragment(); - expect(renderSpy).toBeCalledTimes(1); - const actualData = renderSpy.mock.calls[0][0]; - renderSingularFragment({}, container); - expect(renderSpy).toBeCalledTimes(2); - const actualData2 = renderSpy.mock.calls[1][0]; - expect(actualData).toBe(actualData2); -}); + ReactTestingLibrary.act(() => { + setEnvironment(newEnvironment); + }); -it('should render plural fragment without error when data is available', () => { - renderPluralFragment(); - assertFragmentResults([ - { - id: '1', - name: 'Alice', - ...createFragmentRef('1', pluralQuery), - }, - { - id: '2', - name: 'Bob', - ...createFragmentRef('2', pluralQuery), - }, - ]); -}); + assertFragmentResults({ + id: '1', + name: 'Alice in a different env', + ...createFragmentRef('1', singularQuery), + }); -it('should return the same data object if rendered multiple times: plural fragment', () => { - const container = renderPluralFragment(); - expect(renderSpy).toBeCalledTimes(1); - const actualData = renderSpy.mock.calls[0][0]; - renderPluralFragment({}, container); - expect(renderSpy).toBeCalledTimes(2); - const actualData2 = renderSpy.mock.calls[1][0]; - expect(actualData).toBe(actualData2); -}); + ReactTestingLibrary.act(() => { + newEnvironment.commitPayload(singularQuery, { + node: { + __typename: 'User', + id: '1', + // Update name + name: 'Alice in Wonderland', + username: null, + }, + }); + }); + assertFragmentResults({ + id: '1', + // Assert that name is updated + name: 'Alice in Wonderland', + ...createFragmentRef('1', singularQuery), + }); + }); -it('Returns [] when the fragment ref is [] (for plural fragments)', () => { - const container = renderPluralFragment({usersRef: []}); - assertFragmentResults([]); - TestRenderer.act(() => { - container?.unmount(); - }); -}); + it('should render singular fragment without error when data is available', () => { + renderSingularFragment(); + assertFragmentResults({ + id: '1', + name: 'Alice', + ...createFragmentRef('1', singularQuery), + }); + }); -it('Returns null when the fragment ref is null (for plural fragments)', () => { - const container = renderPluralFragment({usersRef: null}); - assertFragmentResults(null); - TestRenderer.act(() => { - container?.unmount(); - }); -}); + it('should return the same data object if rendered multiple times: singular fragment', () => { + const result = renderSingularFragment(); + expect(renderSpy).toBeCalledTimes(1); + const actualData = renderSpy.mock.calls[0][0]; + renderSingularFragment({}, result.rerender); + expect(renderSpy).toBeCalledTimes(2); + const actualData2 = renderSpy.mock.calls[1][0]; + expect(actualData).toEqual(actualData2); + }); + + it('should render plural fragment without error when data is available', () => { + renderPluralFragment(); + assertFragmentResults([ + { + id: '1', + name: 'Alice', + ...createFragmentRef('1', pluralQuery), + }, + { + id: '2', + name: 'Bob', + ...createFragmentRef('2', pluralQuery), + }, + ]); + }); + + it('should return the same data object if rendered multiple times: plural fragment', () => { + const result = renderPluralFragment(); + expect(renderSpy).toBeCalledTimes(1); + const actualData = renderSpy.mock.calls[0][0]; + renderPluralFragment({}, result?.rerender); + expect(renderSpy).toBeCalledTimes(2); + const actualData2 = renderSpy.mock.calls[1][0]; + expect(actualData).toEqual(actualData2); + }); + + it('Returns [] when the fragment ref is [] (for plural fragments)', () => { + const container = renderPluralFragment({usersRef: []}); + assertFragmentResults([]); + ReactTestingLibrary.act(() => { + container?.unmount(); + }); + }); + + it('Returns null when the fragment ref is null (for plural fragments)', () => { + const container = renderPluralFragment({usersRef: null}); + assertFragmentResults(null); + ReactTestingLibrary.act(() => { + container?.unmount(); + }); + }); + }, +); diff --git a/packages/react-relay/relay-hooks/__tests__/useFragment-with-required-test.js b/packages/react-relay/relay-hooks/__tests__/useFragment-with-required-test.js index adb9ffeda6c1e..a516ba5f72dde 100644 --- a/packages/react-relay/relay-hooks/__tests__/useFragment-with-required-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useFragment-with-required-test.js @@ -40,6 +40,7 @@ test('@required(action: LOG) gets logged even if no data is "missing"', () => { node(id: $id) { ... on User { ...useFragmentWithRequiredTestUserFragment + @dangerously_unaliased_fixme } } } diff --git a/packages/react-relay/relay-hooks/__tests__/useFragmentNode-react-double-effects-test.js b/packages/react-relay/relay-hooks/__tests__/useFragmentNode-react-double-effects-test.js index 09b26d7a12c0c..c8302b1b4d2d7 100644 --- a/packages/react-relay/relay-hooks/__tests__/useFragmentNode-react-double-effects-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useFragmentNode-react-double-effects-test.js @@ -27,7 +27,6 @@ let gqlFragment; let variables; let renderSpy; -// TODO(T83890478): enable once double invoked effects lands in xplat describe.skip('useFragmentNode-react-double-effects-test', () => { beforeEach(() => { jest.mock('scheduler', () => require('../../__tests__/mockScheduler')); @@ -42,6 +41,7 @@ describe.skip('useFragmentNode-react-double-effects-test', () => { query useFragmentNodeReactDoubleEffectsTestUserQuery($id: ID!) { node(id: $id) { ...useFragmentNodeReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -109,6 +109,7 @@ describe.skip('useFragmentNode-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice', 'render: Alice', 'commit: Alice', 'cleanup: Alice', @@ -130,6 +131,7 @@ describe.skip('useFragmentNode-react-double-effects-test', () => { // Assert render state of component after double invoked effects expect(renderLogs).toEqual([ + 'render: Alice Updated', 'render: Alice Updated', 'cleanup: Alice', 'commit: Alice Updated', diff --git a/packages/react-relay/relay-hooks/__tests__/useFragmentNode-required-test.js b/packages/react-relay/relay-hooks/__tests__/useFragmentNode-required-test.js index 624a730a6735f..8baa28178959f 100644 --- a/packages/react-relay/relay-hooks/__tests__/useFragmentNode-required-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useFragmentNode-required-test.js @@ -67,7 +67,7 @@ beforeEach(() => { const gqlSingularQuery = graphql` query useFragmentNodeRequiredTestUserQuery($id: ID!) { node(id: $id) { - ...useFragmentNodeRequiredTestUserFragment + ...useFragmentNodeRequiredTestUserFragment @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useFragmentNode-test.js b/packages/react-relay/relay-hooks/__tests__/useFragmentNode-test.js index 8e1a821ec2679..95ae8068ea74c 100644 --- a/packages/react-relay/relay-hooks/__tests__/useFragmentNode-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useFragmentNode-test.js @@ -258,7 +258,7 @@ describe.each([ gqlSingularQuery = graphql` query useFragmentNodeTestUserQuery($id: ID!, $scale: Float!) { node(id: $id) { - ...useFragmentNodeTestUserFragment + ...useFragmentNodeTestUserFragment @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useIsParentQueryActive-test.js b/packages/react-relay/relay-hooks/__tests__/useIsParentQueryActive-test.js index fa10600a44101..3c9a621a025b8 100644 --- a/packages/react-relay/relay-hooks/__tests__/useIsParentQueryActive-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useIsParentQueryActive-test.js @@ -75,7 +75,7 @@ beforeEach(() => { query = graphql` query useIsParentQueryActiveTestUserQuery($id: ID!) { node(id: $id) { - ...useIsParentQueryActiveTestUserFragment + ...useIsParentQueryActiveTestUserFragment @dangerously_unaliased_fixme } } `; @@ -364,7 +364,9 @@ it('updates the component when a pending owner fetch with multiple payloads comp query = graphql` query useIsParentQueryActiveTestUserDeferQuery($id: ID!) { node(id: $id) { - ...useIsParentQueryActiveTestUserFragment @defer + ...useIsParentQueryActiveTestUserFragment + @dangerously_unaliased_fixme + @defer } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-activity-test.js b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-activity-test.js index 6dfcf8e9c42ca..16a17776422b9 100644 --- a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-activity-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-activity-test.js @@ -177,6 +177,7 @@ beforeEach(() => { const originalDisposable = originalRetain(...args); return { dispose: () => { + // $FlowFixMe[prop-missing] release(args[0].variables); originalDisposable.dispose(); }, @@ -189,6 +190,7 @@ beforeEach(() => { id name ...useLazyLoadQueryNodeActivityTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -236,12 +238,18 @@ it('fetches and renders the query data', async () => { expectToBeRendered(renderFn, data); }); -it('does not dispose and GC the query when hiding', async () => { - const store = new Store(new RecordSource(), { +it('does not dispose and GC the query when hiding within store TTL', async () => { + const queryCacheExpirationTime = 1000; + const source = new RecordSource(); + const store = new Store(source, { gcScheduler: run => run(), gcReleaseBufferSize: 0, + shouldRetainWithinTTL_EXPERIMENTAL: true, + queryCacheExpirationTime, }); jest.spyOn(store, 'scheduleGC'); + const currentTime = Date.now(); + jest.spyOn(global.Date, 'now').mockImplementation(() => currentTime); environment = createMockEnvironment({ store, }); @@ -284,22 +292,108 @@ it('does not dispose and GC the query when hiding', async () => { // Assert that GC doesn't run since the query doesn't // incorrectly get fully released (which would trigger GC) - // TODO: GC should not run here expect(store.scheduleGC).toHaveBeenCalledTimes(1); + expect(source.toJSON()).toEqual({ + '1': { + __id: '1', + __typename: 'User', + id: '1', + name: 'Bob', + }, + 'client:root': { + __id: 'client:root', + __typename: '__Root', + 'node(id:"1")': { + __ref: '1', + }, + }, + }); + + ReactTestingLibrary.act(() => { + setMode('visible'); + }); + + expect(source.toJSON()).toEqual({ + '1': { + __id: '1', + __typename: 'User', + id: '1', + name: 'Bob', + }, + 'client:root': { + __id: 'client:root', + __typename: '__Root', + 'node(id:"1")': { + __ref: '1', + }, + }, + }); +}); + +it('disposes and GCs the query when hiding past query TTL in the store', async () => { + const queryCacheExpirationTime = 1000; + const source = new RecordSource(); + const store = new Store(source, { + gcScheduler: run => run(), + gcReleaseBufferSize: 0, + shouldRetainWithinTTL_EXPERIMENTAL: true, + queryCacheExpirationTime, + }); + jest.spyOn(store, 'scheduleGC'); + let currentTime = Date.now(); + jest.spyOn(global.Date, 'now').mockImplementation(() => currentTime); + environment = createMockEnvironment({ + store, + }); + // Render the component + const instance = await render( + environment, + , + ); - // Assert that a new request was not started + expect(instance?.asFragment().textContent).toEqual('Fallback'); + expectToHaveFetched(environment, query); + expect(renderFn).not.toBeCalled(); // $FlowFixMe[method-unbinding] added when improving typing for this parameters - expect(environment.execute).toHaveBeenCalledTimes(1); // TODO: shouldn't fetch + expect(environment.retain).toHaveBeenCalledTimes(1); + // $FlowFixMe[method-unbinding] added when improving typing for this parameters + environment.execute.mockClear(); + renderFn.mockClear(); + + await ReactTestingLibrary.act(() => { + environment.mock.resolve(gqlQuery, { + data: { + node: { + __typename: 'User', + id: '1', + name: 'Bob', + }, + }, + }); + }); + + const data = environment.lookup(query.fragment).data; + expectToBeRendered(renderFn, data); + // $FlowFixMe[method-unbinding] added when improving typing for this parameters + expect(environment.retain).toHaveBeenCalledTimes(1); + renderFn.mockClear(); + + currentTime += queryCacheExpirationTime; + ReactTestingLibrary.act(() => { + setMode('hidden'); + }); + + expect(store.scheduleGC).toHaveBeenCalledTimes(1); + expect(source.toJSON()).toEqual({}); ReactTestingLibrary.act(() => { setMode('visible'); }); - // $FlowFixMe[method-unbinding] added when improving typing for this parameters - expect(environment.retain).toHaveBeenCalledTimes(2); // TODO: shouldn't need to retain again + expect(source.toJSON()).toEqual({}); }); -it('does not dispose the temporary retain when hiding before commiting', async () => { +it('does not dispose the temporary retain when hiding before committing', async () => { const instance = ReactTestingLibrary.render( diff --git a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-fast-refresh-test.js b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-fast-refresh-test.js index 79272299be85e..f54904cb2b53c 100644 --- a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-fast-refresh-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-fast-refresh-test.js @@ -54,6 +54,8 @@ function expectToHaveFetched( liveConfigId?: ?string, metadata?: {[key: string]: mixed}, onSubscribe?: () => void, + onResume?: (pauseTimeMs: number) => void, + onPause?: (mqttConnectionIsOk: boolean, internetIsOk: boolean) => void, poll?: ?number, transactionId?: ?string, }, @@ -102,6 +104,7 @@ describe('useLazyLoadQueryNode-fast-refresh', () => { id name ...useLazyLoadQueryNodeFastRefreshTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-react-double-effects-test.js b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-react-double-effects-test.js index 34a18f86ebcfc..8ce92ed01811b 100644 --- a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-react-double-effects-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-react-double-effects-test.js @@ -61,6 +61,7 @@ describe.skip('useLazyLoadQueryNode-react-double-effects', () => { id name ...useLazyLoadQueryNodeReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -71,7 +72,9 @@ describe.skip('useLazyLoadQueryNode-react-double-effects', () => { node(id: $id) { id name - ...useLazyLoadQueryNodeReactDoubleEffectsTestUserFragment @defer + ...useLazyLoadQueryNodeReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme + @defer } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-test.js b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-test.js index e6f2d66fa4723..fe8b6634cd28a 100644 --- a/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useLazyLoadQueryNode-test.js @@ -195,6 +195,7 @@ beforeEach(() => { const originalDisposable = originalRetain(...args); return { dispose: () => { + // $FlowFixMe[prop-missing] release(args[0].variables); originalDisposable.dispose(); }, @@ -206,7 +207,7 @@ beforeEach(() => { node(id: $id) { id name - ...useLazyLoadQueryNodeTestUserFragment + ...useLazyLoadQueryNodeTestUserFragment @dangerously_unaliased_fixme } } `; @@ -750,7 +751,9 @@ describe('with @defer and re-rendering', () => { gqlQuery = graphql` query useLazyLoadQueryNodeTest1Query($id: ID) { node(id: $id) { - ...useLazyLoadQueryNodeTestDeferFragment @defer + ...useLazyLoadQueryNodeTestDeferFragment + @dangerously_unaliased_fixme + @defer } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/usePaginationFragment-test.js b/packages/react-relay/relay-hooks/__tests__/usePaginationFragment-test.js index 0e741a6b14651..e2719e83f41c2 100644 --- a/packages/react-relay/relay-hooks/__tests__/usePaginationFragment-test.js +++ b/packages/react-relay/relay-hooks/__tests__/usePaginationFragment-test.js @@ -176,6 +176,19 @@ function expectFragmentResults( renderSpy.mockClear(); } +function expectFragmentLastResult(expectedCall: { + data: $FlowFixMe, + isLoadingNext: boolean, + isLoadingPrevious: boolean, + hasNext: boolean, + hasPrevious: boolean, +}) { + TestRenderer.act(() => jest.runAllImmediates()); + const lastIdx = renderSpy.mock.calls.length - 1; + assertCall(expectedCall, lastIdx); + renderSpy.mockClear(); +} + function resolveQuery(payload: mixed) { TestRenderer.act(() => { dataSource.next(payload); @@ -283,6 +296,7 @@ beforeEach(() => { ) { node(id: $id) { ...usePaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby) } } @@ -300,6 +314,7 @@ beforeEach(() => { node(id: $id) { actor { ...usePaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby) } } @@ -317,6 +332,7 @@ beforeEach(() => { viewer { actor { ...usePaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby) } } @@ -332,6 +348,7 @@ beforeEach(() => { ) { node(id: $id) { ...usePaginationFragmentTestUserFragment + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: true, orderby: ["name"]) } } @@ -348,6 +365,7 @@ beforeEach(() => { ) { node(id: $id) { ...usePaginationFragmentTestUserFragmentWithStreaming + @dangerously_unaliased_fixme @arguments(isViewerFriendLocal: $isViewerFriend, orderby: $orderby) } } @@ -4312,6 +4330,152 @@ describe.each([ }, ]); }); + + it('resets `isLoading` to false, hen loadMore gets interrupted by refresh, and useLoadMore does not trigger a reset', () => { + RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX = true; + renderFragment(); + expectFragmentResults([ + { + data: initialUser, + isLoadingNext: false, + isLoadingPrevious: false, + hasNext: true, + hasPrevious: false, + }, + ]); + + TestRenderer.act(() => { + loadNext(1); + }); + + expectFragmentResults([ + { + data: initialUser, + isLoadingNext: true, + isLoadingPrevious: false, + hasNext: true, + hasPrevious: false, + }, + ]); + fetch.mockClear(); + + TestRenderer.act(() => { + refetch( + { + cursor: null, + }, + { + fetchPolicy: 'network-only', + }, + ); + }); + + const refetchVariables = { + after: null, + before: null, + first: 1, + isViewerFriendLocal: false, + last: null, + orderby: ['name'], + scale: null, + id: '1', + }; + paginationQuery = createOperationDescriptor( + gqlPaginationQuery, + refetchVariables, + {force: true}, + ); + + const REFETCH_DATA = { + data: { + node: { + __typename: 'User', + id: '1', + name: 'Alice', + friends: { + edges: [ + { + cursor: 'cursor:100', + node: { + __typename: 'User', + id: 'node:100', + name: 'name:node:100', + username: 'username:node:100', + }, + }, + ], + pageInfo: { + endCursor: 'cursor:100', + hasNextPage: true, + hasPreviousPage: false, + startCursor: 'cursor:100', + }, + }, + }, + }, + }; + resolveQuery(REFETCH_DATA); + + const expectedUser = { + id: '1', + name: 'Alice', + friends: { + edges: [ + { + cursor: 'cursor:100', + node: { + __typename: 'User', + id: 'node:100', + name: 'name:node:100', + ...createFragmentRef('node:100', paginationQuery), + }, + }, + ], + pageInfo: { + endCursor: 'cursor:100', + hasNextPage: true, + hasPreviousPage: false, + startCursor: 'cursor:100', + }, + }, + }; + + // loadNext gets interrupted by refetch, and `reset()` in useLoadMore triggers + expectFragmentLastResult({ + data: expectedUser, + isLoadingNext: false, + isLoadingPrevious: false, + hasNext: true, + hasPrevious: false, + }); + + // loadNext gets interrupted by refetch, and `reset()` in useLoadMore doesn't trigger + // because fragmentIdentifier doesn't change + TestRenderer.act(() => { + loadNext(1); + }); + TestRenderer.act(() => { + refetch( + { + cursor: null, + }, + { + fetchPolicy: 'network-only', + }, + ); + }); + + resolveQuery(REFETCH_DATA); + expectFragmentLastResult({ + data: expectedUser, + isLoadingNext: false, + isLoadingPrevious: false, + hasNext: true, + hasPrevious: false, + }); + + RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX = false; + }); }); describe('paginating @fetchable types', () => { diff --git a/packages/react-relay/relay-hooks/__tests__/usePrefetchableForwardPaginationFragment_EXPERIMENTAL-test.js b/packages/react-relay/relay-hooks/__tests__/usePrefetchableForwardPaginationFragment-test.js similarity index 87% rename from packages/react-relay/relay-hooks/__tests__/usePrefetchableForwardPaginationFragment_EXPERIMENTAL-test.js rename to packages/react-relay/relay-hooks/__tests__/usePrefetchableForwardPaginationFragment-test.js index 02f2c980ba6b4..f377c5a79cbb8 100644 --- a/packages/react-relay/relay-hooks/__tests__/usePrefetchableForwardPaginationFragment_EXPERIMENTAL-test.js +++ b/packages/react-relay/relay-hooks/__tests__/usePrefetchableForwardPaginationFragment-test.js @@ -11,9 +11,9 @@ 'use strict'; -import type {usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$key} from './__generated__/usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user.graphql'; +import type {usePrefetchableForwardPaginationFragmentTest_user$key} from './__generated__/usePrefetchableForwardPaginationFragmentTest_user.graphql'; -const usePrefetchableForwardPaginationFragment_EXPERIMENTAL = require('../usePrefetchableForwardPaginationFragment_EXPERIMENTAL'); +const usePrefetchableForwardPaginationFragment = require('../usePrefetchableForwardPaginationFragment'); const React = require('react'); const {RelayEnvironmentProvider} = require('react-relay/hooks'); const {act, create} = require('react-test-renderer'); @@ -37,8 +37,9 @@ let hasNextSpy; let isLoadingNextSpy; component Container( - userRef: ?usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user$key, + userRef: ?usePrefetchableForwardPaginationFragmentTest_user$key, minimalEdgesToFetch: number = 1, + UNSTABLE_extraVariables?: mixed, ) { const { edges, @@ -47,9 +48,9 @@ component Container( refetch: _refetch, hasNext, isLoadingNext, - } = usePrefetchableForwardPaginationFragment_EXPERIMENTAL( + } = usePrefetchableForwardPaginationFragment( graphql` - fragment usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user on User + fragment usePrefetchableForwardPaginationFragmentTest_user on User @refetchable( queryName: "usePrefetchableForwardPaginationFragmentRefetchQuery" ) { @@ -70,7 +71,9 @@ component Container( userRef, BUFFER_SIZE, null, - {}, + { + UNSTABLE_extraVariables, + }, minimalEdgesToFetch, ); loadMore = loadNext; @@ -102,7 +105,7 @@ beforeEach(() => { query = createOperationDescriptor( graphql` - query usePrefetchableForwardPaginationFragmentEXPERIMENTALTestQuery( + query usePrefetchableForwardPaginationFragmentTestQuery( $id: ID! $after: ID $first: Int @@ -110,7 +113,8 @@ beforeEach(() => { $last: Int ) { node(id: $id) { - ...usePrefetchableForwardPaginationFragmentEXPERIMENTALTest_user + ...usePrefetchableForwardPaginationFragmentTest_user + @dangerously_unaliased_fixme } } `, @@ -997,3 +1001,109 @@ it('should fetch the amount of items enough to fulfill the product and cache', ( 4, ); }); + +it('getServerEdges should return all unfiltered server edges', () => { + const fragmentKey = environment.lookup(query.fragment).data?.node; + // render the initial page + let app; + const extraVariablesFn = jest.fn(); + // $FlowFixMe[missing-local-annot] + const getExtraVariables = function ({hasNext, getServerEdges}) { + const edges = getServerEdges(); + extraVariablesFn(hasNext, edges); + }; + act(() => { + app = create( + + + + + , + ); + }); + if (app == null) { + throw new Error('app should not be null'); + } + expect(app.toJSON()).toEqual('node1/0'); + + // Prefetches 2 more + expect(environment.mock.getAllOperations().length).toBe(1); + expect(environment.mock.getAllOperations()[0].fragment.variables.first).toBe( + 2, + ); + + expect(extraVariablesFn).toBeCalledTimes(1); + expect(extraVariablesFn).toBeCalledWith(true, [ + { + cursor: 'cursor:1', + node: {__typename: 'User', id: 'node:1', name: 'node1'}, + }, + ]); + extraVariablesFn.mockClear(); + + act(() => { + environment.mock.resolveMostRecentOperation({ + data: { + node: { + __typename: 'User', + id: '1', + name: 'Alice', + friends: { + edges: [ + { + cursor: 'cursor:2', + node: { + __typename: 'User', + id: 'node:2', + name: 'node2', + username: 'username:node:2', + }, + }, + { + cursor: 'cursor:3', + node: { + __typename: 'User', + id: 'node:3', + name: 'node3', + username: 'username:node:3', + }, + }, + ], + pageInfo: { + startCursor: 'cursor:3', + endCursor: 'cursor:3', + hasNextPage: true, + hasPreviousPage: true, + }, + }, + }, + }, + }); + }); + + act(() => { + loadMore(1); + }); + + // 2 edges in display but 3 server edges loaded in total + expect(app.toJSON()).toEqual('node1,node2/1'); + expect(extraVariablesFn).toBeCalledTimes(1); + expect(extraVariablesFn).toBeCalledWith(true, [ + { + cursor: 'cursor:1', + node: {__typename: 'User', id: 'node:1', name: 'node1'}, + }, + { + cursor: 'cursor:2', + node: {__typename: 'User', id: 'node:2', name: 'node2'}, + }, + { + cursor: 'cursor:3', + node: {__typename: 'User', id: 'node:3', name: 'node3'}, + }, + ]); +}); diff --git a/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-provided-variables-test.js b/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-provided-variables-test.js index 3bcce8c726f13..7ba7ddcf8f985 100644 --- a/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-provided-variables-test.js +++ b/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-provided-variables-test.js @@ -72,12 +72,13 @@ const queryPV = graphql` node(id: $id) { id ...usePreloadedQueryProvidedVariablesTest_Fragment + @dangerously_unaliased_fixme } } `; const preloadableConcreteRequestPV = { - kind: 'PreloadableConcreteRequest', + kind: 'PreloadableConcreteRequest' as const, params: queryPV.params, }; @@ -262,6 +263,7 @@ describe('usePreloadedQuery provided variables (%s)', () => { query usePreloadedQueryProvidedVariablesTest_badQuery($id: ID!) { node(id: $id) { ...usePreloadedQueryProvidedVariablesTest_badFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-react-double-effects-test.js b/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-react-double-effects-test.js index 78cb799ca293d..90f9bb0180564 100644 --- a/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-react-double-effects-test.js +++ b/packages/react-relay/relay-hooks/__tests__/usePreloadedQuery-react-double-effects-test.js @@ -126,6 +126,7 @@ describe.skip('usePreloadedQuery-react-double-effects', () => { id name ...usePreloadedQueryReactDoubleEffectsTestFragment + @dangerously_unaliased_fixme } } `; @@ -134,7 +135,9 @@ describe.skip('usePreloadedQuery-react-double-effects', () => { node(id: $id) { id name - ...usePreloadedQueryReactDoubleEffectsTestFragment @defer + ...usePreloadedQueryReactDoubleEffectsTestFragment + @dangerously_unaliased_fixme + @defer } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-live-query-test.js b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-live-query-test.js index 46b45544d4327..4e5e908bf8897 100644 --- a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-live-query-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-live-query-test.js @@ -346,7 +346,7 @@ it('does not release or cancel the query before the new component tree unsuspend let transitionToSecondRoute; function ConcurrentWrapper() { - const [route, setRoute] = React.useState('FIRST'); + const [route, setRoute] = React.useState<'FIRST' | 'SECOND'>('FIRST'); transitionToSecondRoute = () => React.startTransition(() => setRoute('SECOND')); diff --git a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-multiple-calls-test.js b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-multiple-calls-test.js index 5a8540d577d1e..4e2ab8ec7bd50 100644 --- a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-multiple-calls-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-multiple-calls-test.js @@ -39,7 +39,7 @@ const query = graphql` `; const preloadableConcreteRequest = { - kind: 'PreloadableConcreteRequest', + kind: 'PreloadableConcreteRequest' as const, params: query.params, }; diff --git a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-react-double-effects-test.js b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-react-double-effects-test.js index 183feff6ac13f..8dba9b03137d2 100644 --- a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-react-double-effects-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-react-double-effects-test.js @@ -35,6 +35,8 @@ function expectToHaveFetched( liveConfigId?: ?string, metadata?: {[key: string]: mixed}, onSubscribe?: () => void, + onResume?: (pauseTimeMs: number) => void, + onPause?: (mqttConnectionIsOk: boolean, internetIsOk: boolean) => void, poll?: ?number, transactionId?: ?string, }, @@ -119,6 +121,7 @@ describe.skip('useQueryLoader-react-double-effects', () => { id name ...useQueryLoaderReactDoubleEffectsTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-test.js b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-test.js index 4bed819a18791..6f1689fa5904d 100644 --- a/packages/react-relay/relay-hooks/__tests__/useQueryLoader-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useQueryLoader-test.js @@ -405,7 +405,7 @@ describe.each([ let transitionToSecondRoute; function ConcurrentWrapper() { - const [route, setRoute] = React.useState('FIRST'); + const [route, setRoute] = React.useState<'FIRST' | 'SECOND'>('FIRST'); transitionToSecondRoute = () => React.startTransition(() => setRoute('SECOND')); diff --git a/packages/react-relay/relay-hooks/__tests__/useRefetchableFragment-test.js b/packages/react-relay/relay-hooks/__tests__/useRefetchableFragment-test.js index 89d95e192d86a..4986d08a6db4c 100644 --- a/packages/react-relay/relay-hooks/__tests__/useRefetchableFragment-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useRefetchableFragment-test.js @@ -96,7 +96,7 @@ describe('useRefetchableFragment', () => { gqlQuery = graphql` query useRefetchableFragmentTestUserQuery($id: ID!, $scale: Float!) { node(id: $id) { - ...useRefetchableFragmentTestUserFragment + ...useRefetchableFragmentTestUserFragment @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-test.js b/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-test.js index a360ec56fe025..6bf01e10f15ec 100644 --- a/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-test.js @@ -236,6 +236,7 @@ describe.each([['New', useRefetchableFragmentInternal]])( ) { node(id: $id) { ...useRefetchableFragmentNodeTestUserFragment + @dangerously_unaliased_fixme } } `; @@ -247,6 +248,7 @@ describe.each([['New', useRefetchableFragmentInternal]])( node(id: $id) { actor { ...useRefetchableFragmentNodeTestUserFragment + @dangerously_unaliased_fixme } } } @@ -258,6 +260,7 @@ describe.each([['New', useRefetchableFragmentInternal]])( ) { node(id: $id) { ...useRefetchableFragmentNodeTestUserFragmentWithArgs + @dangerously_unaliased_fixme @arguments(scaleLocal: $scale) } } @@ -268,6 +271,7 @@ describe.each([['New', useRefetchableFragmentInternal]])( ) { node(id: $id) { ...useRefetchableFragmentNodeTestUserFragmentWithArgs + @dangerously_unaliased_fixme @arguments(scaleLocal: 16) } } @@ -3727,6 +3731,7 @@ describe.each([['New', useRefetchableFragmentInternal]])( ) { node(id: $nodeID) { ...useRefetchableFragmentNodeTest3Fragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-with-suspense-transition-test.js b/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-with-suspense-transition-test.js index 4dc57953b52db..7d8f447612f6d 100644 --- a/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-with-suspense-transition-test.js +++ b/packages/react-relay/relay-hooks/__tests__/useRefetchableFragmentNode-with-suspense-transition-test.js @@ -216,6 +216,7 @@ describe('useRefetchableFragmentNode with useTransition', () => { ) { node(id: $id) { ...useRefetchableFragmentNodeWithSuspenseTransitionTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/react-relay/relay-hooks/legacy/FragmentResource.js b/packages/react-relay/relay-hooks/legacy/FragmentResource.js index 4f4289db7cadf..00041c6331b68 100644 --- a/packages/react-relay/relay-hooks/legacy/FragmentResource.js +++ b/packages/react-relay/relay-hooks/legacy/FragmentResource.js @@ -558,13 +558,10 @@ class FragmentResourceImpl { _throwOrLogErrorsInSnapshot(snapshot: SingularOrPluralSnapshot) { if (Array.isArray(snapshot)) { snapshot.forEach(s => { - handlePotentialSnapshotErrors(this._environment, s.errorResponseFields); + handlePotentialSnapshotErrors(this._environment, s.fieldErrors); }); } else { - handlePotentialSnapshotErrors( - this._environment, - snapshot.errorResponseFields, - ); + handlePotentialSnapshotErrors(this._environment, snapshot.fieldErrors); } } @@ -763,7 +760,7 @@ class FragmentResourceImpl { missingLiveResolverFields: currentSnapshot.missingLiveResolverFields, seenRecords: currentSnapshot.seenRecords, selector: currentSnapshot.selector, - errorResponseFields: currentSnapshot.errorResponseFields, + fieldErrors: currentSnapshot.fieldErrors, }; if (updatedData !== renderData) { const result = getFragmentResult( diff --git a/packages/react-relay/relay-hooks/loadEntryPoint.js b/packages/react-relay/relay-hooks/loadEntryPoint.js index 0a1d8ee112259..2097105b0f3e6 100644 --- a/packages/react-relay/relay-hooks/loadEntryPoint.js +++ b/packages/react-relay/relay-hooks/loadEntryPoint.js @@ -62,6 +62,12 @@ function loadEntryPoint< const {environmentProviderOptions, options, parameters, variables} = query; + // $FlowFixMe[prop-missing] Exists for types that wrap EntryPoint + if (options?.includeIf === false) { + // don't preload this query since the includeIf is false + return; + } + const environment = environmentProvider.getEnvironment( environmentProviderOptions, ); diff --git a/packages/react-relay/relay-hooks/loadQuery.js b/packages/react-relay/relay-hooks/loadQuery.js index 978b54f89c132..e79bc2634b6a0 100644 --- a/packages/react-relay/relay-hooks/loadQuery.js +++ b/packages/react-relay/relay-hooks/loadQuery.js @@ -28,6 +28,7 @@ import type { RequestIdentifier, RequestParameters, } from 'relay-runtime'; +import type {OperationAvailability} from 'relay-runtime/store/RelayStoreTypes'; const invariant = require('invariant'); const { @@ -130,6 +131,7 @@ function loadQuery< let didMakeNetworkRequest = false; const makeNetworkRequest = ( params: RequestParameters, + checkOperation?: () => OperationAvailability, ): Observable => { // N.B. this function is called synchronously or not at all // didMakeNetworkRequest is safe to rely on in the returned value @@ -160,7 +162,16 @@ function loadQuery< 'raw-network-request-' + getRequestIdentifier(params, variables); const observable = fetchQueryDeduped(environment, identifier, () => { const network = environment.getNetwork(); - return network.execute(params, variables, networkCacheConfig); + return network.execute( + params, + variables, + networkCacheConfig, + undefined, + undefined, + undefined, + undefined, + checkOperation, + ); }); const {unsubscribe} = observable.subscribe({ @@ -247,13 +258,18 @@ function loadQuery< // then we do nothing. const shouldFetch = fetchPolicy !== 'store-or-network' || + // environment.check can trigger store updates through missing field handlers, + // short circuiting the check avoids unnecessary updates environment.check(operation).status !== 'available'; if (shouldFetch) { executeDeduped(operation, () => { // N.B. Since we have the operation synchronously available here, // we can immediately fetch and execute the operation. - const networkObservable = makeNetworkRequest(concreteRequest.params); + const networkObservable = makeNetworkRequest( + concreteRequest.params, + () => environment.check(operation), + ); const executeObservable = executeWithNetworkSource( operation, networkObservable, diff --git a/packages/react-relay/relay-hooks/preloadQuery_DEPRECATED.js b/packages/react-relay/relay-hooks/preloadQuery_DEPRECATED.js index e6ab0ec4f89ff..d42a9eaeda220 100644 --- a/packages/react-relay/relay-hooks/preloadQuery_DEPRECATED.js +++ b/packages/react-relay/relay-hooks/preloadQuery_DEPRECATED.js @@ -24,6 +24,7 @@ import type { GraphQLResponse, GraphQLTaggedNode, IEnvironment, + OperationAvailability, OperationType, Subscription, } from 'relay-runtime'; @@ -167,12 +168,17 @@ function preloadQueryDeduped( }`; const prevQueryEntry = pendingQueries.get(cacheKey); - const availability = - fetchPolicy === STORE_OR_NETWORK_DEFAULT && query != null && query != null + function checkOperation(): OperationAvailability { + return query != null ? environment.check( createOperationDescriptor(query, variables, networkCacheConfig), ) : {status: 'missing'}; + } + const availability = + fetchPolicy === STORE_OR_NETWORK_DEFAULT + ? checkOperation() + : {status: 'missing'}; let nextQueryEntry: ?PendingQueryEntry; if (availability.status === 'available' && query != null) { @@ -203,7 +209,16 @@ function preloadQueryDeduped( } } else if (prevQueryEntry == null || prevQueryEntry.kind !== 'network') { // Should fetch but we're not already fetching: fetch! - const source = network.execute(params, variables, networkCacheConfig, null); + const source = network.execute( + params, + variables, + networkCacheConfig, + null, + undefined, + undefined, + undefined, + checkOperation, + ); const subject = new ReplaySubject(); nextQueryEntry = { cacheKey, diff --git a/packages/react-relay/relay-hooks/readFragmentInternal.js b/packages/react-relay/relay-hooks/readFragmentInternal.js index 4bde1922432ae..8c28ddf1ca0bf 100644 --- a/packages/react-relay/relay-hooks/readFragmentInternal.js +++ b/packages/react-relay/relay-hooks/readFragmentInternal.js @@ -83,13 +83,10 @@ function handlePotentialSnapshotErrorsForState( state: FragmentState, ): void { if (state.kind === 'singular') { - handlePotentialSnapshotErrors( - environment, - state.snapshot.errorResponseFields, - ); + handlePotentialSnapshotErrors(environment, state.snapshot.fieldErrors); } else if (state.kind === 'plural') { for (const snapshot of state.snapshots) { - handlePotentialSnapshotErrors(environment, snapshot.errorResponseFields); + handlePotentialSnapshotErrors(environment, snapshot.fieldErrors); } } } diff --git a/packages/react-relay/relay-hooks/useEntryPointLoader.js b/packages/react-relay/relay-hooks/useEntryPointLoader.js index 6be26c0f94751..3b63e7c05dd83 100644 --- a/packages/react-relay/relay-hooks/useEntryPointLoader.js +++ b/packages/react-relay/relay-hooks/useEntryPointLoader.js @@ -48,7 +48,9 @@ type UseEntryPointLoaderHookReturnType< type NullEntryPointReference = { kind: 'NullEntryPointReference', }; -const initialNullEntryPointReferenceState = {kind: 'NullEntryPointReference'}; +const initialNullEntryPointReferenceState: NullEntryPointReference = { + kind: 'NullEntryPointReference', +}; hook useLoadEntryPoint< TEntryPointParams: {...}, @@ -122,7 +124,7 @@ hook useLoadEntryPoint< const disposeEntryPoint = useCallback(() => { if (isMountedRef.current) { - const nullEntryPointReference = { + const nullEntryPointReference: NullEntryPointReference = { kind: 'NullEntryPointReference', }; undisposedEntryPointReferencesRef.current.add(nullEntryPointReference); diff --git a/packages/react-relay/relay-hooks/useFragmentInternal_CURRENT.js b/packages/react-relay/relay-hooks/useFragmentInternal_CURRENT.js index 5b8252dec4bef..4e7da2fb89fff 100644 --- a/packages/react-relay/relay-hooks/useFragmentInternal_CURRENT.js +++ b/packages/react-relay/relay-hooks/useFragmentInternal_CURRENT.js @@ -111,13 +111,10 @@ function handlePotentialSnapshotErrorsForState( state: FragmentState, ): void { if (state.kind === 'singular') { - handlePotentialSnapshotErrors( - environment, - state.snapshot.errorResponseFields, - ); + handlePotentialSnapshotErrors(environment, state.snapshot.fieldErrors); } else if (state.kind === 'plural') { for (const snapshot of state.snapshots) { - handlePotentialSnapshotErrors(environment, snapshot.errorResponseFields); + handlePotentialSnapshotErrors(environment, snapshot.fieldErrors); } } } @@ -153,7 +150,7 @@ function handleMissedUpdates( missingLiveResolverFields: currentSnapshot.missingLiveResolverFields, seenRecords: currentSnapshot.seenRecords, selector: currentSnapshot.selector, - errorResponseFields: currentSnapshot.errorResponseFields, + fieldErrors: currentSnapshot.fieldErrors, }; return [ updatedData !== state.snapshot.data, @@ -177,7 +174,7 @@ function handleMissedUpdates( missingLiveResolverFields: currentSnapshot.missingLiveResolverFields, seenRecords: currentSnapshot.seenRecords, selector: currentSnapshot.selector, - errorResponseFields: currentSnapshot.errorResponseFields, + fieldErrors: currentSnapshot.fieldErrors, }; if (updatedData !== snapshot.data) { didMissUpdates = true; diff --git a/packages/react-relay/relay-hooks/useFragmentInternal_EXPERIMENTAL.js b/packages/react-relay/relay-hooks/useFragmentInternal_EXPERIMENTAL.js index 68f35c2d65d56..190fdab6aed9d 100644 --- a/packages/react-relay/relay-hooks/useFragmentInternal_EXPERIMENTAL.js +++ b/packages/react-relay/relay-hooks/useFragmentInternal_EXPERIMENTAL.js @@ -123,13 +123,10 @@ function handlePotentialSnapshotErrorsForState( state: FragmentState, ): void { if (state.kind === 'singular') { - handlePotentialSnapshotErrors( - environment, - state.snapshot.errorResponseFields, - ); + handlePotentialSnapshotErrors(environment, state.snapshot.fieldErrors); } else if (state.kind === 'plural') { for (const snapshot of state.snapshots) { - handlePotentialSnapshotErrors(environment, snapshot.errorResponseFields); + handlePotentialSnapshotErrors(environment, snapshot.fieldErrors); } } } @@ -165,7 +162,7 @@ function handleMissedUpdates( missingLiveResolverFields: currentSnapshot.missingLiveResolverFields, seenRecords: currentSnapshot.seenRecords, selector: currentSnapshot.selector, - errorResponseFields: currentSnapshot.errorResponseFields, + fieldErrors: currentSnapshot.fieldErrors, }; return [ updatedData !== state.snapshot.data, @@ -191,7 +188,7 @@ function handleMissedUpdates( missingLiveResolverFields: currentSnapshot.missingLiveResolverFields, seenRecords: currentSnapshot.seenRecords, selector: currentSnapshot.selector, - errorResponseFields: currentSnapshot.errorResponseFields, + fieldErrors: currentSnapshot.fieldErrors, }; if (updatedData !== snapshot.data) { didMissUpdates = true; @@ -577,6 +574,7 @@ hook useFragmentInternal_EXPERIMENTAL( selector: ?ReaderSelector, environment: IEnvironment, } | null>(null); + // $FlowFixMe[react-rule-hook] - the condition is static useEffect(() => { const storeSubscription = storeSubscriptionRef.current; if (storeSubscription != null) { @@ -629,6 +627,7 @@ hook useFragmentInternal_EXPERIMENTAL( environment: state.environment, }; }, [state]); + // $FlowFixMe[react-rule-hook] - the condition is static useEffect(() => { if (storeSubscriptionRef.current == null && state.kind !== 'bailout') { const dispose = subscribeToSnapshot(state.environment, state, setState); diff --git a/packages/react-relay/relay-hooks/useLazyLoadQuery.js b/packages/react-relay/relay-hooks/useLazyLoadQuery.js index e8a11ae60e739..a56779b00ec5e 100644 --- a/packages/react-relay/relay-hooks/useLazyLoadQuery.js +++ b/packages/react-relay/relay-hooks/useLazyLoadQuery.js @@ -32,23 +32,23 @@ const { export type UseLazyLoadQueryHookType = hook ( gqlQuery: Query, variables: TVariables, - options?: { + options?: $ReadOnly<{ fetchKey?: string | number, fetchPolicy?: FetchPolicy, networkCacheConfig?: CacheConfig, UNSTABLE_renderPolicy?: RenderPolicy, - }, + }>, ) => TData; hook useLazyLoadQuery( gqlQuery: Query, variables: TVariables, - options?: { + options?: $ReadOnly<{ fetchKey?: string | number, fetchPolicy?: FetchPolicy, networkCacheConfig?: CacheConfig, UNSTABLE_renderPolicy?: RenderPolicy, - }, + }>, ): TData { const environment = useRelayEnvironment(); diff --git a/packages/react-relay/relay-hooks/useLoadMoreFunction.js b/packages/react-relay/relay-hooks/useLoadMoreFunction.js index 633dd229346c8..8a3d616fa5f92 100644 --- a/packages/react-relay/relay-hooks/useLoadMoreFunction.js +++ b/packages/react-relay/relay-hooks/useLoadMoreFunction.js @@ -138,6 +138,8 @@ hook useLoadMoreFunction_CURRENT( }; }, [disposeFetch]); + const isRequestInvalid = fragmentData == null || isParentQueryActive; + const loadMore = useCallback( ( count: number, @@ -166,11 +168,8 @@ hook useLoadMoreFunction_CURRENT( } const fragmentSelector = getSelector(fragmentNode, fragmentRef); - if ( - isFetchingRef.current === true || - fragmentData == null || - isParentQueryActive - ) { + + if (isFetchingRef.current === true || isRequestInvalid) { if (fragmentSelector == null) { warning( false, @@ -271,8 +270,7 @@ hook useLoadMoreFunction_CURRENT( disposeFetch, completeFetch, isFetchingRef, - isParentQueryActive, - fragmentData, + isRequestInvalid, fragmentNode.name, fragmentRef, componentDisplayName, diff --git a/packages/react-relay/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js b/packages/react-relay/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js index 7f6e40f1e7eb4..764152458f714 100644 --- a/packages/react-relay/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js +++ b/packages/react-relay/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js @@ -135,6 +135,8 @@ hook useLoadMoreFunction_EXPERIMENTAL( connectionPathInFragmentData, ); + const isRequestInvalid = fragmentData == null || isParentQueryActive; + const isMountedRef = useIsMountedRef(); const loadMore = useCallback( ( @@ -164,11 +166,8 @@ hook useLoadMoreFunction_EXPERIMENTAL( } const fragmentSelector = getSelector(fragmentNode, fragmentRef); - if ( - fetchStatusRef.current.kind === 'fetching' || - fragmentData == null || - isParentQueryActive - ) { + + if (fetchStatusRef.current.kind === 'fetching' || isRequestInvalid) { if (fragmentSelector == null) { warning( false, @@ -267,8 +266,7 @@ hook useLoadMoreFunction_EXPERIMENTAL( identifierValue, direction, cursor, - isParentQueryActive, - fragmentData, + isRequestInvalid, fragmentNode.name, fragmentRef, componentDisplayName, diff --git a/packages/react-relay/relay-hooks/usePaginationFragment.js b/packages/react-relay/relay-hooks/usePaginationFragment.js index 35a15b714a207..fe1e4041fb6ef 100644 --- a/packages/react-relay/relay-hooks/usePaginationFragment.js +++ b/packages/react-relay/relay-hooks/usePaginationFragment.js @@ -28,6 +28,7 @@ const useRelayEnvironment = require('./useRelayEnvironment'); const useStaticFragmentNodeWarning = require('./useStaticFragmentNodeWarning'); const {useCallback, useDebugValue, useState} = require('react'); const { + RelayFeatureFlags, getFragment, getFragmentIdentifier, getPaginationMetadata, @@ -196,6 +197,9 @@ hook useLoadMore( start: () => setIsLoadingMore(true), complete: () => setIsLoadingMore(false), error: () => setIsLoadingMore(false), + unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX + ? () => setIsLoadingMore(false) + : undefined, }; const handleReset = () => setIsLoadingMore(false); const [loadMore, hasMore, disposeFetch] = useLoadMoreFunction({ diff --git a/packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment.js b/packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment.js new file mode 100644 index 0000000000000..0e125e2329095 --- /dev/null +++ b/packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment.js @@ -0,0 +1,435 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall relay + */ + +'use strict'; + +import type {RefetchFn} from './useRefetchableFragment'; +import type {Options} from './useRefetchableFragmentInternal'; +import type {FragmentType, Variables} from 'relay-runtime'; +import type {PrefetchableRefetchableFragment} from 'relay-runtime'; + +const useFragment = require('./useFragment'); +const useLoadMoreFunction = require('./useLoadMoreFunction'); +const useRefetchableFragmentInternal = require('./useRefetchableFragmentInternal'); +const useRelayEnvironment = require('./useRelayEnvironment'); +const useStaticFragmentNodeWarning = require('./useStaticFragmentNodeWarning'); +const invariant = require('invariant'); +const { + useCallback, + useDebugValue, + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState, +} = require('react'); +const { + getFragment, + getFragmentIdentifier, + getPaginationMetadata, +} = require('relay-runtime'); +const { + ConnectionInterface, + RelayFeatureFlags, + getSelector, + getValueAtPath, +} = require('relay-runtime'); + +type LoadMoreFn = ( + count: number, + options?: { + onComplete?: (Error | null) => void, + UNSTABLE_extraVariables?: Partial, + }, +) => void; + +export type ReturnType = { + // NOTE: This type ensures that the type of the returned data is either: + // - nullable if the provided ref type is nullable + // - non-nullable if the provided ref type is non-nullable + data: [+key: TKey] extends [+key: {+$fragmentSpreads: mixed, ...}] + ? TData + : ?TData, + loadNext: LoadMoreFn, + hasNext: boolean, + isLoadingNext: boolean, + refetch: RefetchFn, + edges: TEdgeData, +}; + +type LoadMoreOptions = { + UNSTABLE_extraVariables?: Partial, + onComplete?: (Error | null) => void, +}; + +export type GetExtraVariablesFn = ({ + hasNext: boolean, + data: [+key: TKey] extends [+key: {+$fragmentSpreads: mixed, ...}] + ? TData + : ?TData, + getServerEdges: () => TEdgeData, +}) => Partial; + +hook usePrefetchableForwardPaginationFragment< + TFragmentType: FragmentType, + TVariables: Variables, + TData, + TEdgeData, + TKey: ?{+$fragmentSpreads: TFragmentType, ...}, +>( + fragmentInput: PrefetchableRefetchableFragment< + TFragmentType, + TData, + TEdgeData, + TVariables, + >, + parentFragmentRef: TKey, + bufferSize: number, + initialSize?: ?number, + prefetchingLoadMoreOptions?: { + UNSTABLE_extraVariables?: + | Partial + | GetExtraVariablesFn, + onComplete?: (Error | null) => void, + }, + minimalFetchSize: number = 1, + disablePrefetching?: boolean = false, +): ReturnType { + const fragmentNode = getFragment(fragmentInput); + useStaticFragmentNodeWarning( + fragmentNode, + 'first argument of usePrefetchableForwardPaginationFragment()', + ); + const componentDisplayName = 'usePrefetchableForwardPaginationFragment()'; + + const {connectionPathInFragmentData, paginationRequest, paginationMetadata} = + getPaginationMetadata(fragmentNode, componentDisplayName); + + const {fragmentData, fragmentRef, refetch} = useRefetchableFragmentInternal< + {variables: TVariables, response: TData}, + {data?: TData}, + >(fragmentNode, parentFragmentRef, componentDisplayName); + // TODO: Get rid of `getFragmentIdentifier` + const fragmentIdentifier = getFragmentIdentifier(fragmentNode, fragmentRef); + + const edgeKeys = useMemo(() => { + const connection = getValueAtPath( + fragmentData, + connectionPathInFragmentData, + ); + if (connection == null) { + return null; + } + const {EDGES} = ConnectionInterface.get(); + // $FlowFixMe[incompatible-use] + return connection[EDGES]; + }, [connectionPathInFragmentData, fragmentData]); + + const sourceSize = edgeKeys == null ? -1 : edgeKeys.length; + + const [_numInUse, setNumInUse] = useState( + initialSize != null ? initialSize : sourceSize, + ); + let numInUse = _numInUse; + // We can only reset the source size when the component is + // updated with new edgeKeys + if (_numInUse === -1 && sourceSize !== -1) { + numInUse = initialSize != null ? initialSize : sourceSize; + setNumInUse(numInUse); + } + + const environment = useRelayEnvironment(); + const [isLoadingMore, reallySetIsLoadingMore] = useState(false); + const [isRefetching, setIsRefetching] = useState(false); + const availableSizeRef = useRef(0); + // Schedule this update since it must be observed by components at the same + // batch as when hasNext changes. hasNext is read from the store and store + // updates are scheduled, so this must be scheduled too. + const setIsLoadingMore = useCallback( + (value: boolean) => { + const schedule = environment.getScheduler()?.schedule; + if (schedule) { + schedule(() => { + reallySetIsLoadingMore(value); + }); + } else { + reallySetIsLoadingMore(value); + } + }, + [environment], + ); + + // `isLoadingMore` state is updated in a low priority, internally we need + // to synchronously get the loading state to decide whether to load more + const isLoadingMoreRef = useRef(false); + + const observer = useMemo(() => { + function setIsLoadingFalse() { + isLoadingMoreRef.current = false; + setIsLoadingMore(false); + } + return { + start: () => { + isLoadingMoreRef.current = true; + // We want to make sure that `isLoadingMore` is updated immediately, to avoid + // product code triggering multiple `loadMore` calls + reallySetIsLoadingMore(true); + }, + complete: setIsLoadingFalse, + error: setIsLoadingFalse, + unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX + ? setIsLoadingFalse + : undefined, + }; + }, [setIsLoadingMore]); + const handleReset = useCallback(() => { + if (!isRefetching) { + // Do not reset items count during refetching + const schedule = environment.getScheduler()?.schedule; + if (schedule) { + schedule(() => { + setNumInUse(-1); + }); + } else { + setNumInUse(-1); + } + } + isLoadingMoreRef.current = false; + setIsLoadingMore(false); + }, [environment, isRefetching, setIsLoadingMore]); + + const [loadMore, hasNext, disposeFetchNext] = useLoadMoreFunction( + { + componentDisplayName, + connectionPathInFragmentData, + direction: 'forward', + fragmentData, + fragmentIdentifier, + fragmentNode, + fragmentRef, + paginationMetadata, + paginationRequest, + observer, + onReset: handleReset, + }, + ); + + useLayoutEffect(() => { + // Make sure `availableSize` is updated before `showMore` from current render can be called + availableSizeRef.current = sourceSize - numInUse; + }, [numInUse, sourceSize]); + + const prefetchingUNSTABLE_extraVariables = + prefetchingLoadMoreOptions?.UNSTABLE_extraVariables; + const prefetchingOnComplete = prefetchingLoadMoreOptions?.onComplete; + + const showMore = useCallback( + (numToAdd: number, options?: LoadMoreOptions) => { + // Matches the behavior of `usePaginationFragment`. If there is a `loadMore` ongoing, + // the hook handles making the `loadMore` a no-op. + if (!isLoadingMoreRef.current || availableSizeRef.current >= 0) { + // Preemtively update `availableSizeRef`, so if two `loadMore` is called in the same tick, + // a second `loadMore` can be no-op + availableSizeRef.current -= numToAdd; + + setNumInUse(lastNumInUse => { + return lastNumInUse + numToAdd; + }); + + // If the product needs more items from network, load the amount needed to fullfil + // the requirement and cache, capped at the current amount defined by product + if (!isLoadingMoreRef.current && availableSizeRef.current < 0) { + loadMore( + Math.max( + minimalFetchSize, + Math.min(numToAdd, bufferSize - availableSizeRef.current), + ), + // Keep options For backward compatibility + options ?? { + onComplete: prefetchingOnComplete, + UNSTABLE_extraVariables: + typeof prefetchingUNSTABLE_extraVariables === 'function' + ? // $FlowFixMe[incompatible-call] + prefetchingUNSTABLE_extraVariables({ + hasNext, + // $FlowFixMe[incompatible-call] + data: fragmentData, + getServerEdges: () => { + const selector = getSelector( + // $FlowFixMe[incompatible-call] + edgesFragment, + edgeKeys, + ); + if (selector == null) { + // $FlowFixMe[incompatible-call] + return []; + } + invariant( + selector.kind === 'PluralReaderSelector', + 'Expected a plural selector', + ); + // $FlowFixMe[incompatible-call] + return selector.selectors.map( + sel => environment.lookup(sel).data, + ); + }, + }) + : prefetchingUNSTABLE_extraVariables, + }, + ); + } + } + }, + [ + bufferSize, + loadMore, + minimalFetchSize, + edgeKeys, + fragmentData, + prefetchingUNSTABLE_extraVariables, + prefetchingOnComplete, + ], + ); + + const edgesFragment = fragmentInput.metadata?.refetch?.edgesFragment; + invariant( + edgesFragment != null, + 'usePrefetchableForwardPaginationFragment: Expected the edge fragment to be defined, ' + + 'please make sure you have added `prefetchable_pagination: true` to `@connection`', + ); + + // Always try to keep `bufferSize` items in the buffer + // Or load the number of items that have been registred to show + useEffect(() => { + if ( + // Check the ref to avoid infinite `loadMore`, when a `loadMore` has started, + // but `isLoadingMore` isn't updated + !isLoadingMoreRef.current && + // Check the original `isLoadingMore` so when `loadMore` is called, the internal + // `loadMore` hook has been updated with the latest cursor + !isLoadingMore && + !isRefetching && + !disablePrefetching && + hasNext && + (sourceSize - numInUse < bufferSize || numInUse > sourceSize) + ) { + const onComplete = prefetchingOnComplete; + loadMore( + Math.max( + bufferSize - Math.max(sourceSize - numInUse, 0), + numInUse - sourceSize, + minimalFetchSize, + ), + { + onComplete, + UNSTABLE_extraVariables: + typeof prefetchingUNSTABLE_extraVariables === 'function' + ? // $FlowFixMe[incompatible-call] + prefetchingUNSTABLE_extraVariables({ + hasNext, + // $FlowFixMe[incompatible-call] + data: fragmentData, + getServerEdges: () => { + const selector = getSelector(edgesFragment, edgeKeys); + if (selector == null) { + // $FlowFixMe[incompatible-call] + return []; + } + invariant( + selector.kind === 'PluralReaderSelector', + 'Expected a plural selector', + ); + // $FlowFixMe[incompatible-call] + return selector.selectors.map( + sel => environment.lookup(sel).data, + ); + }, + }) + : prefetchingUNSTABLE_extraVariables, + }, + ); + } + }, [ + hasNext, + bufferSize, + isRefetching, + loadMore, + numInUse, + prefetchingUNSTABLE_extraVariables, + prefetchingOnComplete, + sourceSize, + edgeKeys, + isLoadingMore, + minimalFetchSize, + environment, + edgesFragment, + ]); + + const realNumInUse = Math.min(numInUse, sourceSize); + + const derivedEdgeKeys: $ReadOnlyArray = useMemo( + () => edgeKeys?.slice(0, realNumInUse) ?? [], + [edgeKeys, realNumInUse], + ); + + // $FlowExpectedError[incompatible-call] - we know derivedEdgeKeys are the correct keys + const edges: TEdgeData = useFragment(edgesFragment, derivedEdgeKeys); + + const refetchPagination = useCallback( + (variables: TVariables, options?: Options) => { + disposeFetchNext(); + setIsRefetching(true); + return refetch(variables, { + ...options, + onComplete: maybeError => { + // Need to be batched with the store update + const schedule = environment.getScheduler()?.schedule; + if (schedule) { + schedule(() => { + setIsRefetching(false); + setNumInUse(-1); + }); + } else { + setIsRefetching(false); + setNumInUse(-1); + } + options?.onComplete?.(maybeError); + }, + __environment: undefined, + }); + }, + [disposeFetchNext, environment, refetch], + ); + + if (__DEV__) { + // $FlowFixMe[react-rule-hook] + useDebugValue({ + fragment: fragmentNode.name, + data: fragmentData, + hasNext, + isLoadingNext: isLoadingMore, + }); + } + + return { + edges, + // $FlowFixMe[incompatible-return] + data: fragmentData, + loadNext: showMore, + hasNext: hasNext || sourceSize > numInUse, + // Only reflect `isLoadingMore` if the product depends on it, do not refelect + // `isLoaindgMore` state if it is for fufilling the buffer + isLoadingNext: isLoadingMore && numInUse > sourceSize, + refetch: refetchPagination, + }; +} + +module.exports = usePrefetchableForwardPaginationFragment; diff --git a/packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js b/packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js index e8dacf7ab1f9f..c33012315ee35 100644 --- a/packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js +++ b/packages/react-relay/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js @@ -38,6 +38,7 @@ const { } = require('relay-runtime'); const { ConnectionInterface, + RelayFeatureFlags, getSelector, getValueAtPath, } = require('relay-runtime'); @@ -170,25 +171,25 @@ hook usePrefetchableForwardPaginationFragment_EXPERIMENTAL< // to synchronously get the loading state to decide whether to load more const isLoadingMoreRef = useRef(false); - const observer = useMemo( - () => ({ + const observer = useMemo(() => { + function setIsLoadingFalse() { + isLoadingMoreRef.current = false; + setIsLoadingMore(false); + } + return { start: () => { isLoadingMoreRef.current = true; // We want to make sure that `isLoadingMore` is updated immediately, to avoid // product code triggering multiple `loadMore` calls reallySetIsLoadingMore(true); }, - complete: () => { - isLoadingMoreRef.current = false; - setIsLoadingMore(false); - }, - error: () => { - isLoadingMoreRef.current = false; - setIsLoadingMore(false); - }, - }), - [setIsLoadingMore], - ); + complete: setIsLoadingFalse, + error: setIsLoadingFalse, + unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX + ? setIsLoadingFalse + : undefined, + }; + }, [setIsLoadingMore]); const handleReset = useCallback(() => { if (!isRefetching) { // Do not reset items count during refetching diff --git a/packages/react-relay/relay-hooks/useQueryLoader.js b/packages/react-relay/relay-hooks/useQueryLoader.js index 62b09f8607482..a328d308f34ab 100644 --- a/packages/react-relay/relay-hooks/useQueryLoader.js +++ b/packages/react-relay/relay-hooks/useQueryLoader.js @@ -46,7 +46,9 @@ export type UseQueryLoaderLoadQueryOptions = $ReadOnly<{ export type NullQueryReference = { kind: 'NullQueryReference', }; -const initialNullQueryReferenceState = {kind: 'NullQueryReference'}; +const initialNullQueryReferenceState: NullQueryReference = { + kind: 'NullQueryReference', +}; function requestIsLiveQuery< TVariables: Variables, diff --git a/packages/react-relay/relay-hooks/useQueryLoader_EXPERIMENTAL.js b/packages/react-relay/relay-hooks/useQueryLoader_EXPERIMENTAL.js index b060b37740e89..e6c34259e0e22 100644 --- a/packages/react-relay/relay-hooks/useQueryLoader_EXPERIMENTAL.js +++ b/packages/react-relay/relay-hooks/useQueryLoader_EXPERIMENTAL.js @@ -35,7 +35,9 @@ const { } = require('react'); const {getRequest} = require('relay-runtime'); -const initialNullQueryReferenceState = {kind: 'NullQueryReference'}; +const initialNullQueryReferenceState: NullQueryReference = { + kind: 'NullQueryReference', +}; function requestIsLiveQuery< TVariables: Variables, diff --git a/packages/relay-compiler/README.md b/packages/relay-compiler/README.md index 3213c568b1baf..42e965d006291 100644 --- a/packages/relay-compiler/README.md +++ b/packages/relay-compiler/README.md @@ -69,7 +69,7 @@ file sources, and "listen" to the file changes in the "watch" mode. If [string] - `excludes` Directories to ignore under `src`. [array] [default: ["\*\*/node_modules/\*\*", "\*\*/__mocks__/\*\*", "\*\*/__generated__/\*\*"]] -- `schemaExtensions` List of directories with schema extensions. [array] +- `schemaExtensions` List of files or directories with schema extensions. [array] - `schemaConfig` - `nodeInterfaceIdField` Configure the name of the globally unique ID field on the Node interface. Useful if you can't use the default `id` field name. diff --git a/packages/relay-runtime/experimental.js b/packages/relay-runtime/experimental.js index 2b0dda983d6b0..52adff47b38e0 100644 --- a/packages/relay-runtime/experimental.js +++ b/packages/relay-runtime/experimental.js @@ -43,13 +43,13 @@ export type IdOf = [ export type RelayResolverValue = $NonMaybeType; type ErrorResult = { - ok: false, - errors: $ReadOnlyArray, + +ok: false, + +errors: $ReadOnlyArray, }; type OkayResult = { - ok: true, - value: T, + +ok: true, + +value: T, }; export type Result = OkayResult | ErrorResult; @@ -57,13 +57,13 @@ export type Result = OkayResult | ErrorResult; function isValueResult( input: Result, ): input is OkayResult { - return input.ok === true; + return input.ok === (true as const); } function isErrorResult( input: Result, ): input is ErrorResult { - return input.ok === false; + return input.ok === (false as const); } module.exports = { diff --git a/packages/relay-runtime/index.js b/packages/relay-runtime/index.js index 6a5d7c33d5717..5267a78aa80c5 100644 --- a/packages/relay-runtime/index.js +++ b/packages/relay-runtime/index.js @@ -316,6 +316,7 @@ module.exports = { suspenseSentinel, isRequest: GraphQLTag.isRequest, readInlineData, + readFragment: ResolverFragments.readFragment, // Declarative mutation API MutationTypes: RelayDeclarativeMutationConfig.MutationTypes, diff --git a/packages/relay-runtime/multi-actor-environment/__tests__/MultiActorEnvironment-ExecuteMutation-test.js b/packages/relay-runtime/multi-actor-environment/__tests__/MultiActorEnvironment-ExecuteMutation-test.js index 4f3d6e45f080b..40ff0ad56cd0b 100644 --- a/packages/relay-runtime/multi-actor-environment/__tests__/MultiActorEnvironment-ExecuteMutation-test.js +++ b/packages/relay-runtime/multi-actor-environment/__tests__/MultiActorEnvironment-ExecuteMutation-test.js @@ -90,6 +90,7 @@ describe('executeMutation()', () => { node(id: $id) { id ...MultiActorEnvironmentExecuteMutationTestCommentFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/multi-actor-environment/__tests__/__generated__/MultiActorEnvironmentExecuteMutationTestCommentQuery.graphql.js b/packages/relay-runtime/multi-actor-environment/__tests__/__generated__/MultiActorEnvironmentExecuteMutationTestCommentQuery.graphql.js index 6a28916b7b44d..f5a94a729107d 100644 --- a/packages/relay-runtime/multi-actor-environment/__tests__/__generated__/MultiActorEnvironmentExecuteMutationTestCommentQuery.graphql.js +++ b/packages/relay-runtime/multi-actor-environment/__tests__/__generated__/MultiActorEnvironmentExecuteMutationTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "dd845fc72f2a9b2b232f69a75bfae3f7"; + (node/*: any*/).hash = "40c037e72d602053337597c799fb840d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/mutations/__tests__/__generated__/readUpdatableQueryTestRegularQuery.graphql.js b/packages/relay-runtime/mutations/__tests__/__generated__/readUpdatableQueryTestRegularQuery.graphql.js index b4a1a3f0e18fd..a8e4cbf05780f 100644 --- a/packages/relay-runtime/mutations/__tests__/__generated__/readUpdatableQueryTestRegularQuery.graphql.js +++ b/packages/relay-runtime/mutations/__tests__/__generated__/readUpdatableQueryTestRegularQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6a07a0613287459204a27bf01dd58957>> + * @generated SignedSource<<834b1cc235e29a0149d68f66240f01ad>> * @flow * @lightSyntaxTransform * @nogrep @@ -352,7 +352,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "bb6d520f1d382edceed7c6abb54ac6bb"; + (node/*: any*/).hash = "46eea2f5976dc4bcb1af1d5b7479d9b8"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/mutations/__tests__/__generated__/validateMutationTestIsEntitySpreadFragmentMutation.graphql.js b/packages/relay-runtime/mutations/__tests__/__generated__/validateMutationTestIsEntitySpreadFragmentMutation.graphql.js index 5e6f311862944..15431239fb38b 100644 --- a/packages/relay-runtime/mutations/__tests__/__generated__/validateMutationTestIsEntitySpreadFragmentMutation.graphql.js +++ b/packages/relay-runtime/mutations/__tests__/__generated__/validateMutationTestIsEntitySpreadFragmentMutation.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<0248d6513837bacbfbff93448840442e>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -172,7 +172,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "ce0ae1ce1272a3055e3e6a83c36a8c6a"; + (node/*: any*/).hash = "91935f764b37e5a36ce360731e9f75ed"; } module.exports = ((node/*: any*/)/*: Mutation< diff --git a/packages/relay-runtime/mutations/__tests__/commitMutation-test.js b/packages/relay-runtime/mutations/__tests__/commitMutation-test.js index 4cecfe2ea0cce..4976b1c2db255 100644 --- a/packages/relay-runtime/mutations/__tests__/commitMutation-test.js +++ b/packages/relay-runtime/mutations/__tests__/commitMutation-test.js @@ -13,6 +13,7 @@ import type {GraphQLResponseWithoutData} from '../../network/RelayNetworkTypes'; import type {Snapshot} from '../../store/RelayStoreTypes'; import type {RecordSourceSelectorProxy} from '../../store/RelayStoreTypes'; +import type {DeclarativeMutationConfig} from '../RelayDeclarativeMutationConfig'; import type { commitMutationTest4Query$data, commitMutationTest4Query$variables, @@ -116,7 +117,7 @@ describe('Configs: NODE_DELETE', () => { }, }, }); - const configs = [ + const configs: Array = [ { type: 'NODE_DELETE', deletedIDFieldName: 'deletedCommentId', @@ -216,7 +217,7 @@ describe('Configs: RANGE_DELETE', () => { }, }, }; - const configs = [ + const configs: Array = [ { type: 'RANGE_DELETE', parentName: 'feedback', @@ -341,7 +342,7 @@ describe('Configs: RANGE_DELETE', () => { } } `; - const configs = [ + const configs: Array = [ { type: 'RANGE_DELETE', parentName: 'actor', @@ -570,7 +571,7 @@ describe('Configs: RANGE_ADD', () => { }); it('appends new edge', () => { - const configs = [ + const configs: Array = [ { type: 'RANGE_ADD', connectionName: 'topLevelComments', @@ -621,7 +622,7 @@ describe('Configs: RANGE_ADD', () => { }); it('does not overwrite previous edge when appended multiple times', () => { - const configs = [ + const configs: Array = [ { type: 'RANGE_ADD', connectionName: 'topLevelComments', @@ -803,7 +804,7 @@ describe('Configs: RANGE_ADD', () => { }); it('prepends new edge', () => { - const configs = [ + const configs: Array = [ { type: 'RANGE_ADD', connectionName: 'topLevelComments', @@ -854,7 +855,7 @@ describe('Configs: RANGE_ADD', () => { }); it('filters connections then applies the rangeBehavior', () => { - const configs = [ + const configs: Array = [ { type: 'RANGE_ADD', connectionName: 'topLevelComments', diff --git a/packages/relay-runtime/mutations/__tests__/readUpdatableQuery-test.js b/packages/relay-runtime/mutations/__tests__/readUpdatableQuery-test.js index f135da58c1f21..29650cc329048 100644 --- a/packages/relay-runtime/mutations/__tests__/readUpdatableQuery-test.js +++ b/packages/relay-runtime/mutations/__tests__/readUpdatableQuery-test.js @@ -119,7 +119,7 @@ const regularQuery = graphql` } } node(id: "4") { - ...readUpdatableQueryTest_user + ...readUpdatableQueryTest_user @dangerously_unaliased_fixme ... on User { name } diff --git a/packages/relay-runtime/mutations/__tests__/validateMutation-test.js b/packages/relay-runtime/mutations/__tests__/validateMutation-test.js index fe54f29d60252..e7db3b14998a0 100644 --- a/packages/relay-runtime/mutations/__tests__/validateMutation-test.js +++ b/packages/relay-runtime/mutations/__tests__/validateMutation-test.js @@ -760,6 +760,7 @@ describe('validateOptimisticResponse', () => { actorNameChange(input: $input) { actor { ...validateMutationTestEntityFragement + @dangerously_unaliased_fixme } } } diff --git a/packages/relay-runtime/mutations/createUpdatableProxy.js b/packages/relay-runtime/mutations/createUpdatableProxy.js index bf1ea3cde711f..62536a04548e6 100644 --- a/packages/relay-runtime/mutations/createUpdatableProxy.js +++ b/packages/relay-runtime/mutations/createUpdatableProxy.js @@ -181,11 +181,11 @@ function updateProxyFromSelections( case 'ClientEdgeToServerObject': case 'Defer': case 'ModuleImport': - case 'RelayLiveResolver': case 'RequiredField': case 'CatchField': case 'Stream': case 'RelayResolver': + case 'RelayLiveResolver': // These types of reader nodes are not currently handled. throw new Error( 'Encountered an unexpected ReaderSelection variant in RelayRecordSourceProxy. This indicates a bug in Relay.', diff --git a/packages/relay-runtime/mutations/validateMutation.js b/packages/relay-runtime/mutations/validateMutation.js index 9b1f50b965872..06877bdba1474 100644 --- a/packages/relay-runtime/mutations/validateMutation.js +++ b/packages/relay-runtime/mutations/validateMutation.js @@ -145,13 +145,13 @@ if (__DEV__) { return validateModuleImport(context); case 'TypeDiscriminator': return validateAbstractKey(context, selection.abstractKey); - case 'RelayResolver': - case 'RelayLiveResolver': case 'ClientEdgeToClientObject': case 'LinkedHandle': case 'ScalarHandle': case 'Defer': - case 'Stream': { + case 'Stream': + case 'RelayResolver': + case 'RelayLiveResolver': { // TODO(T35864292) - Add missing validations for these types return; } diff --git a/packages/relay-runtime/network/RelayNetworkTypes.js b/packages/relay-runtime/network/RelayNetworkTypes.js index 244edae3fcfed..dd911e94ee68d 100644 --- a/packages/relay-runtime/network/RelayNetworkTypes.js +++ b/packages/relay-runtime/network/RelayNetworkTypes.js @@ -11,6 +11,7 @@ 'use strict'; +import type {OperationAvailability} from '../store/RelayStoreTypes'; import type {RequestParameters} from '../util/RelayConcreteNode'; import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes'; import type RelayObservable, {ObservableFromValue} from './RelayObservable'; @@ -104,6 +105,8 @@ export type ExecuteFunction = ( logRequestInfo?: ?LogRequestInfoFunction, encryptedVariables?: ?string, preprocessResponse?: ?preprocessResponseFunction, + // Run datachecker on the current operation and returns the OperationAvailability + checkOperation?: () => OperationAvailability, ) => RelayObservable; /** diff --git a/packages/relay-runtime/network/RelayObservable.js b/packages/relay-runtime/network/RelayObservable.js index 6d5a11547a320..e155135e2623a 100644 --- a/packages/relay-runtime/network/RelayObservable.js +++ b/packages/relay-runtime/network/RelayObservable.js @@ -614,11 +614,7 @@ if (__DEV__) { // Default implementation of HostReportErrors() in development builds. // Can be replaced by the host application environment. RelayObservable.onUnhandledError((error, isUncaughtThrownError) => { - declare function fail(string): void; - if (typeof fail === 'function') { - // In test environments (Jest), fail() immediately fails the current test. - fail(String(error)); - } else if (isUncaughtThrownError) { + if (isUncaughtThrownError) { // Rethrow uncaught thrown errors on the next frame to avoid breaking // current logic. setTimeout(() => { diff --git a/packages/relay-runtime/network/wrapNetworkWithLogObserver.js b/packages/relay-runtime/network/wrapNetworkWithLogObserver.js index aea0a0f88380a..94918a8b941a6 100644 --- a/packages/relay-runtime/network/wrapNetworkWithLogObserver.js +++ b/packages/relay-runtime/network/wrapNetworkWithLogObserver.js @@ -12,12 +12,17 @@ 'use strict'; import type ActorSpecificEnvironment from '../multi-actor-environment/ActorSpecificEnvironment'; import type RelayModernEnvironment from '../store/RelayModernEnvironment'; +import type { + LogRequestInfoFunction, + OperationAvailability, +} from '../store/RelayStoreTypes'; import type {RequestParameters} from '../util/RelayConcreteNode'; import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes'; import type { GraphQLResponse, INetwork, UploadableMap, + preprocessResponseFunction, } from './RelayNetworkTypes'; import type RelayObservable from './RelayObservable'; import type {Subscription} from './RelayObservable'; @@ -42,6 +47,10 @@ function wrapNetworkWithLogObserver( variables: Variables, cacheConfig: CacheConfig, uploadables?: ?UploadableMap, + _?: ?LogRequestInfoFunction, + encryptedVariables?: ?string, + preprocessResponse?: ?preprocessResponseFunction, + checkOperation?: () => OperationAvailability, ): RelayObservable { const networkRequestId = generateID(); const logObserver = { @@ -89,7 +98,16 @@ function wrapNetworkWithLogObserver( }); }; return network - .execute(params, variables, cacheConfig, uploadables, logRequestInfo) + .execute( + params, + variables, + cacheConfig, + uploadables, + logRequestInfo, + encryptedVariables, + preprocessResponse, + checkOperation, + ) .do(logObserver); }, }; diff --git a/packages/relay-runtime/query/fetchQuery.js b/packages/relay-runtime/query/fetchQuery.js index ae2df100f9e19..c9b81917fd97f 100644 --- a/packages/relay-runtime/query/fetchQuery.js +++ b/packages/relay-runtime/query/fetchQuery.js @@ -138,7 +138,7 @@ function fetchQuery( const fetchPolicy = options?.fetchPolicy ?? 'network-only'; function readData(snapshot: Snapshot): TData { - handlePotentialSnapshotErrors(environment, snapshot.errorResponseFields); + handlePotentialSnapshotErrors(environment, snapshot.fieldErrors); /* $FlowFixMe[incompatible-return] we assume readData returns the right * data just having written it from network or checked availability. */ return snapshot.data; diff --git a/packages/relay-runtime/store/DataChecker.js b/packages/relay-runtime/store/DataChecker.js index 28a6a748d4c6b..747116f7e5621 100644 --- a/packages/relay-runtime/store/DataChecker.js +++ b/packages/relay-runtime/store/DataChecker.js @@ -449,8 +449,6 @@ class DataChecker { this._traverseSelections(selection.fragment.selections, dataID); break; case 'RelayResolver': - this._checkResolver(selection, dataID); - break; case 'RelayLiveResolver': this._checkResolver(selection, dataID); break; diff --git a/packages/relay-runtime/store/OperationExecutor.js b/packages/relay-runtime/store/OperationExecutor.js index 5878a64603dec..e03623c969f5f 100644 --- a/packages/relay-runtime/store/OperationExecutor.js +++ b/packages/relay-runtime/store/OperationExecutor.js @@ -245,6 +245,12 @@ class Executor { cacheConfig: this._operation.request.cacheConfig ?? {}, }); }, + unsubscribe: () => { + this._log({ + name: 'execute.unsubscribe', + executeId: this._executeId, + }); + }, }); if ( @@ -293,7 +299,7 @@ class Executor { } _updateActiveState(): void { - let activeState; + let activeState: ActiveState; switch (this._state) { case 'started': { activeState = 'active'; @@ -606,6 +612,7 @@ class Executor { { actorIdentifier: this._actorIdentifier, getDataID: this._getDataID, + log: this._log, path: [], shouldProcessClientComponents: this._shouldProcessClientComponents, treatMissingFieldsAsNull, @@ -715,6 +722,7 @@ class Executor { { actorIdentifier: this._actorIdentifier, getDataID: this._getDataID, + log: this._log, path: followupPayload.path, treatMissingFieldsAsNull: this._treatMissingFieldsAsNull, shouldProcessClientComponents: this._shouldProcessClientComponents, @@ -797,6 +805,7 @@ class Executor { { actorIdentifier: this._actorIdentifier, getDataID: this._getDataID, + log: this._log, path: [], treatMissingFieldsAsNull: this._treatMissingFieldsAsNull, shouldProcessClientComponents: this._shouldProcessClientComponents, @@ -1253,6 +1262,7 @@ class Executor { { actorIdentifier: this._actorIdentifier, getDataID: this._getDataID, + log: this._log, path: placeholder.path, treatMissingFieldsAsNull: this._treatMissingFieldsAsNull, shouldProcessClientComponents: this._shouldProcessClientComponents, @@ -1480,6 +1490,7 @@ class Executor { const relayPayload = this._normalizeResponse(response, selector, typeName, { actorIdentifier: this._actorIdentifier, getDataID: this._getDataID, + log: this._log, path: [...normalizationPath, responseKey, String(itemIndex)], treatMissingFieldsAsNull: this._treatMissingFieldsAsNull, shouldProcessClientComponents: this._shouldProcessClientComponents, diff --git a/packages/relay-runtime/store/RelayExperimentalGraphResponseTransform.js b/packages/relay-runtime/store/RelayExperimentalGraphResponseTransform.js index 4a95d12c23b0e..a224401c0a33a 100644 --- a/packages/relay-runtime/store/RelayExperimentalGraphResponseTransform.js +++ b/packages/relay-runtime/store/RelayExperimentalGraphResponseTransform.js @@ -222,10 +222,10 @@ export class GraphModeNormalizer { $streamID, __id: dataID, __typename: ROOT_TYPE, - }; + } as RecordChunk; yield { $kind: 'Complete', - }; + } as CompleteChunk; } *_flushFields( @@ -247,9 +247,9 @@ export class GraphModeNormalizer { __typename: typename, __id: cacheKey, $streamID, - }; + } as RecordChunk; } else if (Object.keys(fields).length > 0) { - yield {...fields, $kind: 'Extend', $streamID}; + yield {...fields, $kind: 'Extend', $streamID} as ExtendChunk; } return $streamID; } diff --git a/packages/relay-runtime/store/RelayModernEnvironment.js b/packages/relay-runtime/store/RelayModernEnvironment.js index 2a9a708bd1711..b6921003c290c 100644 --- a/packages/relay-runtime/store/RelayModernEnvironment.js +++ b/packages/relay-runtime/store/RelayModernEnvironment.js @@ -327,13 +327,18 @@ class RelayModernEnvironment implements IEnvironment { operation: OperationDescriptor, }): RelayObservable { return this._execute({ - createSource: () => - this.getNetwork().execute( + createSource: () => { + return this.getNetwork().execute( operation.request.node.params, operation.request.variables, operation.request.cacheConfig || {}, null, - ), + undefined, + undefined, + undefined, + () => this.check(operation), + ); + }, isClientPayload: false, operation, optimisticConfig: null, diff --git a/packages/relay-runtime/store/RelayModernFragmentSpecResolver.js b/packages/relay-runtime/store/RelayModernFragmentSpecResolver.js index b2acf3590d314..5354a2cfcb004 100644 --- a/packages/relay-runtime/store/RelayModernFragmentSpecResolver.js +++ b/packages/relay-runtime/store/RelayModernFragmentSpecResolver.js @@ -14,7 +14,7 @@ import type {ConcreteRequest} from '../util/RelayConcreteNode'; import type {Disposable, Variables} from '../util/RelayRuntimeTypes'; import type { - ErrorResponseFields, + FieldErrors, FragmentMap, FragmentSpecResolver, FragmentSpecResults, @@ -228,7 +228,7 @@ class SelectorResolver { _data: ?SelectorData; _environment: IEnvironment; _isMissingData: boolean; - _errorResponseFields: ?ErrorResponseFields; + _fieldErrors: ?FieldErrors; _rootIsQueryRenderer: boolean; _selector: SingularReaderSelector; _subscription: ?Disposable; @@ -244,7 +244,7 @@ class SelectorResolver { this._callback = callback; this._data = snapshot.data; this._isMissingData = snapshot.isMissingData; - this._errorResponseFields = snapshot.errorResponseFields; + this._fieldErrors = snapshot.fieldErrors; this._environment = environment; this._rootIsQueryRenderer = rootIsQueryRenderer; this._selector = selector; @@ -325,7 +325,7 @@ class SelectorResolver { } } } - handlePotentialSnapshotErrors(this._environment, this._errorResponseFields); + handlePotentialSnapshotErrors(this._environment, this._fieldErrors); return this._data; } @@ -340,7 +340,7 @@ class SelectorResolver { const snapshot = this._environment.lookup(selector); this._data = recycleNodesInto(this._data, snapshot.data); this._isMissingData = snapshot.isMissingData; - this._errorResponseFields = snapshot.errorResponseFields; + this._fieldErrors = snapshot.fieldErrors; this._selector = selector; this._subscription = this._environment.subscribe(snapshot, this._onChange); } @@ -376,7 +376,7 @@ class SelectorResolver { _onChange = (snapshot: Snapshot): void => { this._data = snapshot.data; this._isMissingData = snapshot.isMissingData; - this._errorResponseFields = snapshot.errorResponseFields; + this._fieldErrors = snapshot.fieldErrors; this._callback(); }; } diff --git a/packages/relay-runtime/store/RelayModernStore.js b/packages/relay-runtime/store/RelayModernStore.js index f7deeb40081d4..897bd3978ef3e 100644 --- a/packages/relay-runtime/store/RelayModernStore.js +++ b/packages/relay-runtime/store/RelayModernStore.js @@ -107,6 +107,7 @@ class RelayModernStore implements Store { fetchTime: ?number, }, >; + _shouldRetainWithinTTL_EXPERIMENTAL: boolean; _shouldScheduleGC: boolean; _storeSubscriptions: StoreSubscriptions; _updatedRecordIDs: DataIDSet; @@ -127,6 +128,9 @@ class RelayModernStore implements Store { shouldProcessClientComponents?: ?boolean, resolverContext?: ResolverContext, + // Experimental + shouldRetainWithinTTL_EXPERIMENTAL?: boolean, + // These additional config options are only used if the experimental // @outputType resolver feature is used treatMissingFieldsAsNull?: ?boolean, @@ -147,6 +151,8 @@ class RelayModernStore implements Store { this._gcHoldCounter = 0; this._gcReleaseBufferSize = options?.gcReleaseBufferSize ?? DEFAULT_RELEASE_BUFFER_SIZE; + this._shouldRetainWithinTTL_EXPERIMENTAL = + options?.shouldRetainWithinTTL_EXPERIMENTAL ?? false; this._gcRun = null; this._gcScheduler = options?.gcScheduler ?? resolveImmediate; this._getDataID = options?.getDataID ?? defaultGetDataID; @@ -165,14 +171,15 @@ class RelayModernStore implements Store { () => this._getMutableRecordSource(), this, ); + this._resolverContext = options?.resolverContext; this._storeSubscriptions = new RelayStoreSubscriptions( options?.log, this._resolverCache, + this._resolverContext, ); this._updatedRecordIDs = new Set(); this._shouldProcessClientComponents = options?.shouldProcessClientComponents ?? false; - this._resolverContext = options?.resolverContext; this._treatMissingFieldsAsNull = options?.treatMissingFieldsAsNull ?? false; this._actorIdentifier = options?.actorIdentifier; @@ -315,7 +322,9 @@ class RelayModernStore implements Store { rootEntry.fetchTime <= Date.now() - _queryCacheExpirationTime; if (rootEntryIsStale) { - this._roots.delete(id); + if (!this._shouldRetainWithinTTL_EXPERIMENTAL) { + this._roots.delete(id); + } this.scheduleGC(); } else { this._releaseBuffer.push(id); @@ -325,8 +334,10 @@ class RelayModernStore implements Store { // buffer have a refCount of 0. if (this._releaseBuffer.length > this._gcReleaseBufferSize) { const _id = this._releaseBuffer.shift(); - // $FlowFixMe[incompatible-call] - this._roots.delete(_id); + if (!this._shouldRetainWithinTTL_EXPERIMENTAL) { + // $FlowFixMe[incompatible-call] + this._roots.delete(_id); + } this.scheduleGC(); } } @@ -688,6 +699,14 @@ class RelayModernStore implements Store { }; *_collect(): Generator { + if ( + this._shouldRetainWithinTTL_EXPERIMENTAL && + this._queryCacheExpirationTime == null + ) { + // Null expiration time indicates infinite TTL, so we don't need to + // run GC. + return; + } /* eslint-disable no-labels */ const log = this.__log; top: while (true) { @@ -699,8 +718,30 @@ class RelayModernStore implements Store { const startEpoch = this._currentWriteEpoch; const references = new Set(); - // Mark all records that are traversable from a root - for (const {operation} of this._roots.values()) { + for (const [ + dataID, + {operation, refCount, fetchTime}, + ] of this._roots.entries()) { + if (this._shouldRetainWithinTTL_EXPERIMENTAL) { + // Do not mark records that should be garbage collected + const {_queryCacheExpirationTime} = this; + invariant( + _queryCacheExpirationTime != null, + 'Query cache expiration time should be non-null if executing GC', + ); + const recordHasExpired = + fetchTime == null || + fetchTime <= Date.now() - _queryCacheExpirationTime; + const recordShouldBeCollected = + recordHasExpired && + refCount === 0 && + !this._releaseBuffer.includes(dataID); + if (recordShouldBeCollected) { + continue; + } + } + + // Mark all records that are traversable from a root that is still valid const selector = operation.root; RelayReferenceMarker.mark( this._recordSource, @@ -723,31 +764,36 @@ class RelayModernStore implements Store { } } - // Sweep records without references - if (references.size === 0) { - // Short-circuit if *nothing* is referenced - this._recordSource.clear(); - } else { - // Evict any unreferenced nodes - const storeIDs = this._recordSource.getRecordIDs(); - for (let ii = 0; ii < storeIDs.length; ii++) { - const dataID = storeIDs[ii]; - if (!references.has(dataID)) { - const record = this._recordSource.get(dataID); - if (record != null) { - const maybeResolverSubscription = RelayModernRecord.getValue( - record, - RELAY_RESOLVER_LIVE_STATE_SUBSCRIPTION_KEY, - ); - if (maybeResolverSubscription != null) { - // $FlowFixMe - this value if it is not null, it is a function - maybeResolverSubscription(); - } + // NOTE: It may be tempting to use `this._recordSource.clear()` + // when no references are found, but that would prevent calling + // maybeResolverSubscription() on any records that have an active + // resolver subscription. This would result in a memory leak. + + // Evict any unreferenced nodes + const storeIDs = this._recordSource.getRecordIDs(); + for (let ii = 0; ii < storeIDs.length; ii++) { + const dataID = storeIDs[ii]; + if (!references.has(dataID)) { + const record = this._recordSource.get(dataID); + if (record != null) { + const maybeResolverSubscription = RelayModernRecord.getValue( + record, + RELAY_RESOLVER_LIVE_STATE_SUBSCRIPTION_KEY, + ); + if (maybeResolverSubscription != null) { + // $FlowFixMe - this value if it is not null, it is a function + maybeResolverSubscription(); } - this._recordSource.remove(dataID); + } + this._recordSource.remove(dataID); + if (this._shouldRetainWithinTTL_EXPERIMENTAL) { + // Note: A record that was never retained will not be in the roots map + // but the following line should not throw + this._roots.delete(dataID); } } } + if (log != null) { log({ name: 'store.gc.end', @@ -765,6 +811,7 @@ class RelayModernStore implements Store { return { path, getDataID: this._getDataID, + log: this.__log, treatMissingFieldsAsNull: this._treatMissingFieldsAsNull, shouldProcessClientComponents: this._shouldProcessClientComponents, actorIdentifier: this._actorIdentifier, diff --git a/packages/relay-runtime/store/RelayPublishQueue.js b/packages/relay-runtime/store/RelayPublishQueue.js index b842ea09d1ee8..57ed5920ade57 100644 --- a/packages/relay-runtime/store/RelayPublishQueue.js +++ b/packages/relay-runtime/store/RelayPublishQueue.js @@ -33,6 +33,7 @@ import type { const RelayRecordSourceMutator = require('../mutations/RelayRecordSourceMutator'); const RelayRecordSourceProxy = require('../mutations/RelayRecordSourceProxy'); const RelayRecordSourceSelectorProxy = require('../mutations/RelayRecordSourceSelectorProxy'); +const RelayFeatureFlags = require('../util/RelayFeatureFlags'); const RelayReader = require('./RelayReader'); const RelayRecordSource = require('./RelayRecordSource'); const invariant = require('invariant'); @@ -60,8 +61,10 @@ type PendingUpdater = { const _global: typeof global | $FlowFixMe = typeof global !== 'undefined' ? global - : typeof window !== 'undefined' - ? window + : // $FlowFixMe[cannot-resolve-name] + typeof window !== 'undefined' + ? // $FlowFixMe[cannot-resolve-name] + window : undefined; const applyWithGuard = @@ -219,24 +222,27 @@ class RelayPublishQueue implements PublishQueue { this._pendingOptimisticUpdates.size === 0 && !runWillClearGcHold; - if (__DEV__) { - warning( - !runIsANoop, - 'RelayPublishQueue.run was called, but the call would have been a noop.', - ); - warning( - this._isRunning !== true, - 'A store update was detected within another store update. Please ' + - "make sure new store updates aren't being executed within an " + - 'updater function for a different update.', - ); - this._isRunning = true; - } + warning( + !runIsANoop, + 'RelayPublishQueue.run was called, but the call would have been a noop.', + ); + RelayFeatureFlags.DISALLOW_NESTED_UPDATES + ? invariant( + this._isRunning !== true, + 'A store update was detected within another store update. Please ' + + "make sure new store updates aren't being executed within an " + + 'updater function for a different update.', + ) + : warning( + this._isRunning !== true, + 'A store update was detected within another store update. Please ' + + "make sure new store updates aren't being executed within an " + + 'updater function for a different update.', + ); + this._isRunning = true; if (runIsANoop) { - if (__DEV__) { - this._isRunning = false; - } + this._isRunning = false; return []; } @@ -268,9 +274,7 @@ class RelayPublishQueue implements PublishQueue { this._gcHold = null; } } - if (__DEV__) { - this._isRunning = false; - } + this._isRunning = false; return this._store.notify(sourceOperation, invalidatedStore); } diff --git a/packages/relay-runtime/store/RelayReader.js b/packages/relay-runtime/store/RelayReader.js index 9d22714aeca9e..cf16b204651c4 100644 --- a/packages/relay-runtime/store/RelayReader.js +++ b/packages/relay-runtime/store/RelayReader.js @@ -35,8 +35,8 @@ import type {DataID, Variables} from '../util/RelayRuntimeTypes'; import type { ClientEdgeTraversalInfo, DataIDSet, - ErrorResponseField, - ErrorResponseFields, + FieldError, + FieldErrors, MissingClientEdgeRequestInfo, Record, RecordSource, @@ -49,6 +49,7 @@ import type { import type {Arguments} from './RelayStoreUtils'; import type {EvaluationResult, ResolverCache} from './ResolverCache'; +const RelayFeatureFlags = require('../util/RelayFeatureFlags'); const { isSuspenseSentinel, } = require('./live-resolvers/LiveResolverSuspenseSentinel'); @@ -98,7 +99,7 @@ class RelayReader { _missingClientEdges: Array; _missingLiveResolverFields: Array; _isWithinUnmatchedTypeRefinement: boolean; - _errorResponseFields: ?ErrorResponseFields; + _fieldErrors: ?FieldErrors; _owner: RequestDescriptor; // Exec time resolvers are run before reaching the Relay store so the store already contains // the normalized data; the same as if the data were sent from the server. However, since a @@ -128,10 +129,13 @@ class RelayReader { this._missingLiveResolverFields = []; this._isMissingData = false; this._isWithinUnmatchedTypeRefinement = false; - this._errorResponseFields = null; + this._fieldErrors = null; this._owner = selector.owner; this._useExecTimeResolvers = - this._owner.node.operation.use_exec_time_resolvers ?? false; + this._owner.node.operation.use_exec_time_resolvers ?? + this._owner.node.operation.exec_time_resolvers_enabled_provider?.get() === + true ?? + false; this._recordSource = recordSource; this._seenRecords = new Set(); this._selector = selector; @@ -205,11 +209,11 @@ class RelayReader { missingLiveResolverFields: this._missingLiveResolverFields, seenRecords: this._seenRecords, selector: this._selector, - errorResponseFields: this._errorResponseFields, + fieldErrors: this._fieldErrors, }; } - _maybeAddErrorResponseFields(record: Record, storageKey: string): void { + _maybeAddFieldErrors(record: Record, storageKey: string): void { const errors = RelayModernRecord.getErrors(record, storageKey); if (errors == null) { @@ -217,11 +221,11 @@ class RelayReader { } const owner = this._fragmentName; - if (this._errorResponseFields == null) { - this._errorResponseFields = []; + if (this._fieldErrors == null) { + this._fieldErrors = []; } for (const error of errors) { - this._errorResponseFields.push({ + this._fieldErrors.push({ kind: 'relay_field_payload.error', owner, fieldPath: (error.path ?? []).join('.'), @@ -236,14 +240,14 @@ class RelayReader { if (this._isWithinUnmatchedTypeRefinement) { return; } - if (this._errorResponseFields == null) { - this._errorResponseFields = []; + if (this._fieldErrors == null) { + this._fieldErrors = []; } // we will add the path later const owner = this._fragmentName; - this._errorResponseFields.push( + this._fieldErrors.push( this._selector.node.metadata?.throwOnFieldError ?? false ? { kind: 'missing_expected_data.throw', @@ -282,6 +286,7 @@ class RelayReader { if (record === undefined) { this._markDataAsMissing(''); } + // $FlowFixMe[incompatible-return] return record; } const data = prevData || {}; @@ -308,8 +313,8 @@ class RelayReader { } const owner = this._fragmentName; - if (this._errorResponseFields == null) { - this._errorResponseFields = []; + if (this._fieldErrors == null) { + this._fieldErrors = []; } let fieldName: string; @@ -322,7 +327,7 @@ class RelayReader { switch (selection.action) { case 'THROW': - this._errorResponseFields.push({ + this._fieldErrors.push({ kind: 'missing_required_field.throw', fieldPath: fieldName, owner, @@ -330,7 +335,7 @@ class RelayReader { }); return; case 'LOG': - this._errorResponseFields.push({ + this._fieldErrors.push({ kind: 'missing_required_field.log', fieldPath: fieldName, owner, @@ -361,7 +366,7 @@ class RelayReader { * any fields within them. * * 1. Before traversing into the selection(s) marked as `@catch`, the caller - * stores the previous field errors (`this._errorResponseFields`) in a + * stores the previous field errors (`this._fieldErrors`) in a * variable. * 2. After traversing into the selection(s) marked as `@catch`, the caller * calls this method with the resulting value, the `to` value from the @@ -376,7 +381,7 @@ class RelayReader { _catchErrors( _value: T, to: CatchFieldTo, - previousResponseFields: ?ErrorResponseFields, + previousResponseFields: ?FieldErrors, ): ?T | Result { let value: T | null | Result = _value; switch (to) { @@ -384,10 +389,7 @@ class RelayReader { value = this._asResult(_value); break; case 'NULL': - if ( - this._errorResponseFields != null && - this._errorResponseFields.length > 0 - ) { + if (this._fieldErrors != null && this._fieldErrors.length > 0) { value = null; } break; @@ -395,22 +397,22 @@ class RelayReader { (to: empty); } - const childrenErrorResponseFields = this._errorResponseFields; + const childrenFieldErrors = this._fieldErrors; - this._errorResponseFields = previousResponseFields; + this._fieldErrors = previousResponseFields; // Merge any errors encountered within the @catch with the previous field // errors, but mark them as "handled" first. - if (childrenErrorResponseFields != null) { - if (this._errorResponseFields == null) { - this._errorResponseFields = []; + if (childrenFieldErrors != null) { + if (this._fieldErrors == null) { + this._fieldErrors = []; } - for (let i = 0; i < childrenErrorResponseFields.length; i++) { + for (let i = 0; i < childrenFieldErrors.length; i++) { // We mark any errors encountered within the @catch as "handled" // to ensure that they don't cause the reader to throw, but can // still be logged. - this._errorResponseFields.push( - markFieldErrorHasHandled(childrenErrorResponseFields[i]), + this._fieldErrors.push( + markFieldErrorHasHandled(childrenFieldErrors[i]), ); } } @@ -419,21 +421,18 @@ class RelayReader { /** * Convert a value into a Result object based on the presence of errors in the - * `this._errorResponseFields` array. + * `this._fieldErrors` array. * * **Note**: This method does _not_ mark errors as handled. It is the caller's * responsibility to ensure that errors are marked as handled. */ _asResult(value: T): Result { - if ( - this._errorResponseFields == null || - this._errorResponseFields.length === 0 - ) { + if (this._fieldErrors == null || this._fieldErrors.length === 0) { return {ok: true, value}; } // TODO: Should we be hiding log level events here? - const errors = this._errorResponseFields + const errors = this._fieldErrors .map(error => { switch (error.kind) { case 'relay_field_payload.error': @@ -461,7 +460,7 @@ class RelayReader { (error.kind: empty); invariant( false, - 'Unexpected error errorResponseField kind: %s', + 'Unexpected error fieldError kind: %s', error.kind, ); } @@ -491,9 +490,9 @@ class RelayReader { } break; case 'CatchField': { - const previousResponseFields = this._errorResponseFields; + const previousResponseFields = this._fieldErrors; - this._errorResponseFields = null; + this._fieldErrors = null; const catchFieldValue = this._readClientSideDirectiveField( selection, @@ -662,13 +661,31 @@ class RelayReader { } else { return this._readLink(selection.field, record, data); } + case 'RelayResolver': - return this._readResolverField(selection.field, record, data); - case 'RelayLiveResolver': - return this._readResolverField(selection.field, record, data); + case 'RelayLiveResolver': { + if (this._useExecTimeResolvers) { + return this._readScalar(selection.field, record, data); + } else { + return this._readResolverField(selection.field, record, data); + } + } case 'ClientEdgeToClientObject': case 'ClientEdgeToServerObject': - return this._readClientEdge(selection.field, record, data); + if ( + this._useExecTimeResolvers && + (selection.field.backingField.kind === 'RelayResolver' || + selection.field.backingField.kind === 'RelayLiveResolver') + ) { + const {field} = selection; + if (field.linkedField.plural) { + return this._readPluralLink(field.linkedField, record, data); + } else { + return this._readLink(field.linkedField, record, data); + } + } else { + return this._readClientEdge(selection.field, record, data); + } case 'AliasedInlineFragmentSpread': return this._readAliasedInlineFragment(selection.field, record, data); default: @@ -687,8 +704,8 @@ class RelayReader { data: SelectorData, ): mixed { const parentRecordID = RelayModernRecord.getDataID(record); - const prevErrors = this._errorResponseFields; - this._errorResponseFields = null; + const prevErrors = this._fieldErrors; + this._fieldErrors = null; const result = this._readResolverFieldImpl(field, parentRecordID); const fieldName = field.alias ?? field.name; @@ -726,7 +743,7 @@ class RelayReader { return { data: snapshot.data, isMissingData: snapshot.isMissingData, - errorResponseFields: snapshot.errorResponseFields, + fieldErrors: snapshot.fieldErrors, }; } @@ -739,7 +756,7 @@ class RelayReader { return { data: snapshot.data, isMissingData: snapshot.isMissingData, - errorResponseFields: snapshot.errorResponseFields, + fieldErrors: snapshot.fieldErrors, }; }; @@ -837,23 +854,23 @@ class RelayReader { this._missingLiveResolverFields.push(missingResolverField); } } - if (cachedSnapshot.errorResponseFields != null) { - if (this._errorResponseFields == null) { - this._errorResponseFields = []; + if (cachedSnapshot.fieldErrors != null) { + if (this._fieldErrors == null) { + this._fieldErrors = []; } - for (const error of cachedSnapshot.errorResponseFields) { + for (const error of cachedSnapshot.fieldErrors) { if (this._selector.node.metadata?.throwOnFieldError === true) { // If this fragment is @throwOnFieldError, any destructive error // encountered inside a resolver's fragment is equivilent to the // resolver field having a field error, and we want that to cause this // fragment to throw. So, we propagate all errors as is. - this._errorResponseFields.push(error); + this._fieldErrors.push(error); } else { // If this fragment is _not_ @throwOnFieldError, we will simply // accept that any destructive errors encountered in the resolver's // root fragment will cause the resolver to return null, and well // pass the errors along to the logger marked as "handled". - this._errorResponseFields.push(markFieldErrorHasHandled(error)); + this._fieldErrors.push(markFieldErrorHasHandled(error)); } } } @@ -864,7 +881,7 @@ class RelayReader { // the errors can be attached to this read's snapshot. This allows the error // to be logged. if (resolverError) { - const errorEvent = { + const errorEvent: FieldError = { kind: 'relay_resolver.error', fieldPath, owner: this._fragmentName, @@ -872,10 +889,10 @@ class RelayReader { shouldThrow: this._selector.node.metadata?.throwOnFieldError ?? false, handled: false, }; - if (this._errorResponseFields == null) { - this._errorResponseFields = [errorEvent]; + if (this._fieldErrors == null) { + this._fieldErrors = [errorEvent]; } else { - this._errorResponseFields.push(errorEvent); + this._fieldErrors.push(errorEvent); } } @@ -1068,8 +1085,8 @@ class RelayReader { RelayModernRecord.getDataID(record), prevData, ); - const prevErrors = this._errorResponseFields; - this._errorResponseFields = null; + const prevErrors = this._fieldErrors; + this._fieldErrors = null; const edgeValue = this._traverse( field.linkedField, storeID, @@ -1091,8 +1108,13 @@ class RelayReader { const fieldName = field.alias ?? field.name; const storageKey = getStorageKey(field, this._variables); const value = RelayModernRecord.getValue(record, storageKey); - if (value === null) { - this._maybeAddErrorResponseFields(record, storageKey); + if ( + value === null || + (RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS && + Array.isArray(value) && + value.length === 0) + ) { + this._maybeAddFieldErrors(record, storageKey); } else if (value === undefined) { this._markDataAsMissing(fieldName); } @@ -1111,7 +1133,7 @@ class RelayReader { if (linkedID == null) { data[fieldName] = linkedID; if (linkedID === null) { - this._maybeAddErrorResponseFields(record, storageKey); + this._maybeAddFieldErrors(record, storageKey); } else if (linkedID === undefined) { this._markDataAsMissing(fieldName); } @@ -1128,8 +1150,8 @@ class RelayReader { RelayModernRecord.getDataID(record), prevData, ); - const prevErrors = this._errorResponseFields; - this._errorResponseFields = null; + const prevErrors = this._fieldErrors; + this._fieldErrors = null; // $FlowFixMe[incompatible-variance] const value = this._traverse(field, linkedID, prevData); @@ -1139,7 +1161,7 @@ class RelayReader { } /** - * Adds a set of field errors to `this._errorResponseFields`, ensuring the + * Adds a set of field errors to `this._fieldErrors`, ensuring the * `fieldPath` property of existing field errors are prefixed with the given * `fieldNameOrIndex`. * @@ -1158,8 +1180,8 @@ class RelayReader { * To achieve this, named field readers must do the following to correctly * track error filePaths: * - * 1. Stash the value of `this._errorResponseFields` in a local variable - * 2. Set `this._errorResponseFields` to `null` + * 1. Stash the value of `this._fieldErrors` in a local variable + * 2. Set `this._fieldErrors` to `null` * 3. Traverse into the field * 4. Call this method with the stashed errors and the field's name * @@ -1171,12 +1193,12 @@ class RelayReader { * field error paths. */ _prependPreviousErrors( - prevErrors: ?Array, + prevErrors: ?Array, fieldNameOrIndex: string | number, ): void { - if (this._errorResponseFields != null) { - for (let i = 0; i < this._errorResponseFields.length; i++) { - const event = this._errorResponseFields[i]; + if (this._fieldErrors != null) { + for (let i = 0; i < this._fieldErrors.length; i++) { + const event = this._fieldErrors[i]; if ( event.owner === this._fragmentName && (event.kind === 'missing_expected_data.throw' || @@ -1188,13 +1210,13 @@ class RelayReader { } } if (prevErrors != null) { - for (let i = this._errorResponseFields.length - 1; i >= 0; i--) { - prevErrors.push(this._errorResponseFields[i]); + for (let i = this._fieldErrors.length - 1; i >= 0; i--) { + prevErrors.push(this._fieldErrors[i]); } - this._errorResponseFields = prevErrors; + this._fieldErrors = prevErrors; } } else { - this._errorResponseFields = prevErrors; + this._fieldErrors = prevErrors; } } @@ -1215,7 +1237,7 @@ class RelayReader { if (externalRef === undefined) { this._markDataAsMissing(fieldName); } else if (externalRef === null) { - this._maybeAddErrorResponseFields(record, storageKey); + this._maybeAddFieldErrors(record, storageKey); } return data[fieldName]; } @@ -1243,8 +1265,13 @@ class RelayReader { ): ?mixed { const storageKey = getStorageKey(field, this._variables); const linkedIDs = RelayModernRecord.getLinkedRecordIDs(record, storageKey); - if (linkedIDs === null) { - this._maybeAddErrorResponseFields(record, storageKey); + if ( + linkedIDs === null || + (RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS && + Array.isArray(linkedIDs) && + linkedIDs.length === 0) + ) { + this._maybeAddFieldErrors(record, storageKey); } return this._readLinkedIds(field, linkedIDs, record, data); } @@ -1274,8 +1301,8 @@ class RelayReader { RelayModernRecord.getDataID(record), prevData, ); - const prevErrors = this._errorResponseFields; - this._errorResponseFields = null; + const prevErrors = this._fieldErrors; + this._fieldErrors = null; const linkedArray = prevData || []; linkedIDs.forEach((linkedID, nextIndex) => { if (linkedID == null) { @@ -1295,8 +1322,8 @@ class RelayReader { RelayModernRecord.getDataID(record), prevItem, ); - const prevErrors = this._errorResponseFields; - this._errorResponseFields = null; + const prevErrors = this._fieldErrors; + this._fieldErrors = null; // $FlowFixMe[cannot-write] // $FlowFixMe[incompatible-variance] linkedArray[nextIndex] = this._traverse(field, linkedID, prevItem); @@ -1366,8 +1393,8 @@ class RelayReader { record: Record, data: SelectorData, ) { - const prevErrors = this._errorResponseFields; - this._errorResponseFields = null; + const prevErrors = this._fieldErrors; + this._fieldErrors = null; let fieldValue = this._readInlineFragment( aliasedInlineFragment.fragment, record, @@ -1597,9 +1624,7 @@ class RelayReader { } } -function markFieldErrorHasHandled( - event: ErrorResponseField, -): ErrorResponseField { +function markFieldErrorHasHandled(event: FieldError): FieldError { switch (event.kind) { case 'missing_expected_data.throw': case 'missing_required_field.throw': diff --git a/packages/relay-runtime/store/RelayReferenceMarker.js b/packages/relay-runtime/store/RelayReferenceMarker.js index 8fec7f88f358d..a7f601fd872a7 100644 --- a/packages/relay-runtime/store/RelayReferenceMarker.js +++ b/packages/relay-runtime/store/RelayReferenceMarker.js @@ -38,7 +38,8 @@ const RelayStoreUtils = require('./RelayStoreUtils'); const {generateTypeID} = require('./TypeID'); const invariant = require('invariant'); -const {getStorageKey, getModuleOperationKey} = RelayStoreUtils; +const {getReadTimeResolverStorageKey, getStorageKey, getModuleOperationKey} = + RelayStoreUtils; function mark( recordSource: RecordSource, @@ -216,8 +217,6 @@ class RelayReferenceMarker { this._traverseSelections(selection.fragment.selections, record); break; case 'RelayResolver': - this._traverseResolverField(selection, record); - break; case 'RelayLiveResolver': this._traverseResolverField(selection, record); break; @@ -291,7 +290,7 @@ class RelayReferenceMarker { field: NormalizationResolverField | NormalizationLiveResolverField, record: Record, ): ?DataID { - const storageKey = getStorageKey(field, this._variables); + const storageKey = getReadTimeResolverStorageKey(field, this._variables); const dataID = RelayModernRecord.getLinkedRecordID(record, storageKey); // If the resolver value has been created, we should retain it. diff --git a/packages/relay-runtime/store/RelayResponseNormalizer.js b/packages/relay-runtime/store/RelayResponseNormalizer.js index 62da388182a6e..08fe23180bc06 100644 --- a/packages/relay-runtime/store/RelayResponseNormalizer.js +++ b/packages/relay-runtime/store/RelayResponseNormalizer.js @@ -29,7 +29,9 @@ import type {RelayErrorTrie} from './RelayErrorTrie'; import type { FollowupPayload, HandleFieldPayload, + IdCollisionTypenameLogEvent, IncrementalDataPlaceholder, + LogFunction, MutableRecordSource, NormalizationSelector, Record, @@ -72,6 +74,7 @@ export type GetDataID = ( export type NormalizationOptions = { +getDataID: GetDataID, +treatMissingFieldsAsNull: boolean, + +log: ?LogFunction, +path?: $ReadOnlyArray, +shouldProcessClientComponents?: ?boolean, +actorIdentifier?: ?ActorIdentifier, @@ -116,6 +119,7 @@ class RelayResponseNormalizer { _variables: Variables; _shouldProcessClientComponents: ?boolean; _errorTrie: RelayErrorTrie | null; + _log: ?LogFunction; constructor( recordSource: MutableRecordSource, @@ -134,6 +138,7 @@ class RelayResponseNormalizer { this._recordSource = recordSource; this._variables = variables; this._shouldProcessClientComponents = options.shouldProcessClientComponents; + this._log = options.log; } normalizeResponse( @@ -319,8 +324,6 @@ class RelayResponseNormalizer { this._normalizeActorChange(selection, record, data); break; case 'RelayResolver': - this._normalizeResolver(selection, record, data); - break; case 'RelayLiveResolver': this._normalizeResolver(selection, record, data); break; @@ -472,12 +475,11 @@ class RelayResponseNormalizer { const responseKey = selection.alias || selection.name; const storageKey = getStorageKey(selection, this._variables); const fieldValue = data[responseKey]; - if ( - fieldValue == null || - (RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS && - Array.isArray(fieldValue) && - fieldValue.length === 0) - ) { + const isNoncompliantlyNullish = + RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS && + Array.isArray(fieldValue) && + fieldValue.length === 0; + if (fieldValue == null || isNoncompliantlyNullish) { if (fieldValue === undefined) { // Fields may be missing in the response in two main cases: // - Inside a client extension: the server will not generally return @@ -511,20 +513,27 @@ class RelayResponseNormalizer { return; } } - if (__DEV__) { - if (selection.kind === 'ScalarField') { - this._validateConflictingFieldsWithIdenticalId( - record, - storageKey, - // When using `treatMissingFieldsAsNull` the conflicting validation raises a false positive - // because the value is set using `null` but validated using `fieldValue` which at this point - // will be `undefined`. - // Setting this to `null` matches the value that we actually set to the `fieldValue`. - null, - ); + if (selection.kind === 'ScalarField') { + this._validateConflictingFieldsWithIdenticalId( + record, + storageKey, + // When using `treatMissingFieldsAsNull` the conflicting validation raises a false positive + // because the value is set using `null` but validated using `fieldValue` which at this point + // will be `undefined`. + // Setting this to `null` matches the value that we actually set to the `fieldValue`. + null, + ); + } + if (isNoncompliantlyNullish) { + // We need to preserve the fact that we received an empty list + if (selection.kind === 'LinkedField') { + RelayModernRecord.setLinkedRecordIDs(record, storageKey, []); + } else { + RelayModernRecord.setValue(record, storageKey, []); } + } else { + RelayModernRecord.setValue(record, storageKey, null); } - RelayModernRecord.setValue(record, storageKey, null); const errorTrie = this._errorTrie; if (errorTrie != null) { const errors = getErrorsByKey(errorTrie, responseKey); @@ -536,13 +545,11 @@ class RelayResponseNormalizer { } if (selection.kind === 'ScalarField') { - if (__DEV__) { - this._validateConflictingFieldsWithIdenticalId( - record, - storageKey, - fieldValue, - ); - } + this._validateConflictingFieldsWithIdenticalId( + record, + storageKey, + fieldValue, + ); RelayModernRecord.setValue(record, storageKey, fieldValue); } else if (selection.kind === 'LinkedField') { this._path.push(responseKey); @@ -686,13 +693,11 @@ class RelayResponseNormalizer { 'RelayResponseNormalizer: Expected id on field `%s` to be a string.', storageKey, ); - if (__DEV__) { - this._validateConflictingLinkedFieldsWithIdenticalId( - RelayModernRecord.getLinkedRecordID(record, storageKey), - nextID, - storageKey, - ); - } + this._validateConflictingLinkedFieldsWithIdenticalId( + RelayModernRecord.getLinkedRecordID(record, storageKey), + nextID, + storageKey, + ); RelayModernRecord.setLinkedRecordID(record, storageKey, nextID); let nextRecord = this._recordSource.get(nextID); if (!nextRecord) { @@ -700,7 +705,7 @@ class RelayResponseNormalizer { const typeName = field.concreteType || this._getRecordType(fieldValue); nextRecord = RelayModernRecord.create(nextID, typeName); this._recordSource.set(nextID, nextRecord); - } else if (__DEV__) { + } else { this._validateRecordType(nextRecord, field, fieldValue); } // $FlowFixMe[incompatible-variance] @@ -766,19 +771,15 @@ class RelayResponseNormalizer { const typeName = field.concreteType || this._getRecordType(item); nextRecord = RelayModernRecord.create(nextID, typeName); this._recordSource.set(nextID, nextRecord); - } else if (__DEV__) { + } else { this._validateRecordType(nextRecord, field, item); } - // NOTE: the check to strip __DEV__ code only works for simple - // `if (__DEV__)` - if (__DEV__) { - if (prevIDs) { - this._validateConflictingLinkedFieldsWithIdenticalId( - prevIDs[nextIndex], - nextID, - storageKey, - ); - } + if (prevIDs) { + this._validateConflictingLinkedFieldsWithIdenticalId( + prevIDs[nextIndex], + nextID, + storageKey, + ); } // $FlowFixMe[incompatible-variance] this._traverseSelections(field, nextRecord, item); @@ -796,20 +797,43 @@ class RelayResponseNormalizer { field: NormalizationLinkedField, payload: Object, ): void { - const typeName = field.concreteType ?? this._getRecordType(payload); - const dataID = RelayModernRecord.getDataID(record); - warning( - (isClientID(dataID) && dataID !== ROOT_ID) || - RelayModernRecord.getType(record) === typeName, - 'RelayResponseNormalizer: Invalid record `%s`. Expected %s to be ' + - 'consistent, but the record was assigned conflicting types `%s` ' + - 'and `%s`. The GraphQL server likely violated the globally unique ' + - 'id requirement by returning the same id for different objects.', - dataID, - TYPENAME_KEY, - RelayModernRecord.getType(record), - typeName, - ); + const log = RelayFeatureFlags.ENABLE_STORE_ID_COLLISION_LOGGING; + if (log) { + const typeName = field.concreteType ?? this._getRecordType(payload); + const dataID = RelayModernRecord.getDataID(record); + const shouldLogWarning = + (isClientID(dataID) && dataID !== ROOT_ID) || + RelayModernRecord.getType(record) === typeName; + if (shouldLogWarning) { + const logEvent: IdCollisionTypenameLogEvent = { + name: 'idCollision.typename', + previous_typename: RelayModernRecord.getType(record), + new_typename: typeName, + }; + if (this._log != null) { + this._log(logEvent); + } + } + } + // NOTE: Only emit a warning in DEV + if (__DEV__) { + const typeName = field.concreteType ?? this._getRecordType(payload); + const dataID = RelayModernRecord.getDataID(record); + const shouldLogWarning = + (isClientID(dataID) && dataID !== ROOT_ID) || + RelayModernRecord.getType(record) === typeName; + warning( + shouldLogWarning, + 'RelayResponseNormalizer: Invalid record `%s`. Expected %s to be ' + + 'consistent, but the record was assigned conflicting types `%s` ' + + 'and `%s`. The GraphQL server likely violated the globally unique ' + + 'id requirement by returning the same id for different objects.', + dataID, + TYPENAME_KEY, + RelayModernRecord.getType(record), + typeName, + ); + } } /** @@ -820,14 +844,16 @@ class RelayResponseNormalizer { storageKey: string, fieldValue: mixed, ): void { - // NOTE: Only call this function in DEV + // NOTE: Only emit a warning in DEV if (__DEV__) { + const previousValue = RelayModernRecord.getValue(record, storageKey); const dataID = RelayModernRecord.getDataID(record); - var previousValue = RelayModernRecord.getValue(record, storageKey); - warning( + const shouldLogWarning = storageKey === TYPENAME_KEY || - previousValue === undefined || - areEqual(previousValue, fieldValue), + previousValue === undefined || + areEqual(previousValue, fieldValue); + warning( + shouldLogWarning, 'RelayResponseNormalizer: Invalid record. The record contains two ' + 'instances of the same id: `%s` with conflicting field, %s and its values: %s and %s. ' + 'If two fields are different but share ' + @@ -848,10 +874,11 @@ class RelayResponseNormalizer { nextID: DataID, storageKey: string, ): void { - // NOTE: Only call this function in DEV + // NOTE: Only emit a warning in DEV if (__DEV__) { + const shouldLogWarning = prevID === undefined || prevID === nextID; warning( - prevID === undefined || prevID === nextID, + shouldLogWarning, 'RelayResponseNormalizer: Invalid record. The record contains ' + 'references to the conflicting field, %s and its id values: %s and %s. ' + 'We need to make sure that the record the field points ' + diff --git a/packages/relay-runtime/store/RelayStoreSubscriptions.js b/packages/relay-runtime/store/RelayStoreSubscriptions.js index bfdd489656bb3..7957787c68cb9 100644 --- a/packages/relay-runtime/store/RelayStoreSubscriptions.js +++ b/packages/relay-runtime/store/RelayStoreSubscriptions.js @@ -115,7 +115,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions { missingLiveResolverFields: backup.missingLiveResolverFields, seenRecords: backup.seenRecords, selector: backup.selector, - errorResponseFields: backup.errorResponseFields, + fieldErrors: backup.fieldErrors, }; } else { // This subscription was created during the optimisitic state. We should @@ -185,7 +185,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions { missingLiveResolverFields: nextSnapshot.missingLiveResolverFields, seenRecords: nextSnapshot.seenRecords, selector: nextSnapshot.selector, - errorResponseFields: nextSnapshot.errorResponseFields, + fieldErrors: nextSnapshot.fieldErrors, }: Snapshot); if (__DEV__) { deepFreeze(nextSnapshot); diff --git a/packages/relay-runtime/store/RelayStoreTypes.js b/packages/relay-runtime/store/RelayStoreTypes.js index d2d04fae95b99..6aa4a6ef08188 100644 --- a/packages/relay-runtime/store/RelayStoreTypes.js +++ b/packages/relay-runtime/store/RelayStoreTypes.js @@ -116,7 +116,7 @@ export type NormalizationSelector = { +variables: Variables, }; -export type ErrorResponseField = +export type FieldError = | RelayFieldPayloadErrorEvent | MissingExpectedDataLogEvent | MissingExpectedDataThrowEvent @@ -124,7 +124,7 @@ export type ErrorResponseField = | MissingRequiredFieldLogEvent | MissingRequiredFieldThrowEvent; -export type ErrorResponseFields = Array; +export type FieldErrors = Array; export type ClientEdgeTraversalInfo = { +readerClientEdge: ReaderClientEdgeToServerObject, @@ -149,7 +149,7 @@ export type Snapshot = { +missingClientEdges: null | $ReadOnlyArray, +seenRecords: DataIDSet, +selector: SingularReaderSelector, - +errorResponseFields: ?ErrorResponseFields, + +fieldErrors: ?FieldErrors, }; /** @@ -684,6 +684,11 @@ export type ExecuteCompleteLogEvent = { +executeId: number, }; +export type ExecuteUnsubscribeLogEvent = { + +name: 'execute.unsubscribe', + +executeId: number, +}; + export type ExecuteNormalizeStart = { +name: 'execute.normalize.start', +operation: OperationDescriptor, @@ -781,12 +786,23 @@ export type UseFragmentSubscriptionMissedUpdates = { +hasDataChanges: boolean, }; +/** + * This event is logged when two strong objects share the same id, + * but have different types, resulting in an collision in the store. + */ +export type IdCollisionTypenameLogEvent = { + +name: 'idCollision.typename', + +previous_typename: string, + +new_typename: string, +}; + export type LogEvent = | SuspenseFragmentLogEvent | SuspenseQueryLogEvent | QueryResourceFetchLogEvent | QueryResourceRetainLogEvent | FragmentResourceMissingDataLogEvent + | IdCollisionTypenameLogEvent | PendingOperationFoundLogEvent | NetworkInfoLogEvent | NetworkStartLogEvent @@ -800,6 +816,7 @@ export type LogEvent = | ExecuteAsyncModuleLogEvent | ExecuteErrorLogEvent | ExecuteCompleteLogEvent + | ExecuteUnsubscribeLogEvent | ExecuteNormalizeStart | ExecuteNormalizeEnd | StoreDataCheckerStartEvent @@ -1481,7 +1498,7 @@ export type ConcreteClientEdgeResolverReturnType = { * returns a callback which should be called when the value _may_ have changed. * * While over-notification (subscription notifications when the read value has - * not actually changed) is suported, for performance reasons, it is recommended + * not actually changed) is supported, for performance reasons, it is recommended * that the provider of the LiveState value confirms that the value has indeed * change before notifying Relay of the change. */ diff --git a/packages/relay-runtime/store/RelayStoreUtils.js b/packages/relay-runtime/store/RelayStoreUtils.js index 49ce5e05a770b..f28b68860b8a8 100644 --- a/packages/relay-runtime/store/RelayStoreUtils.js +++ b/packages/relay-runtime/store/RelayStoreUtils.js @@ -15,6 +15,8 @@ import type { NormalizationArgument, NormalizationField, NormalizationHandle, + NormalizationLiveResolverField, + NormalizationResolverField, } from '../util/NormalizationNode'; import type { ReaderActorChange, @@ -28,6 +30,7 @@ import type {Variables} from '../util/RelayRuntimeTypes'; const getRelayHandleKey = require('../util/getRelayHandleKey'); const RelayConcreteNode = require('../util/RelayConcreteNode'); +const RelayFeatureFlags = require('../util/RelayFeatureFlags'); const {stableCopy} = require('../util/stableCopy'); const invariant = require('invariant'); @@ -42,6 +45,8 @@ const ERRORS_KEY: '__errors' = '__errors'; const MODULE_COMPONENT_KEY_PREFIX = '__module_component_'; const MODULE_OPERATION_KEY_PREFIX = '__module_operation_'; +const RELAY_READ_TIME_RESOLVER_KEY_PREFIX = '$r:'; + function getArgumentValue( arg: NormalizationArgument | ReaderArgument, variables: Variables, @@ -163,6 +168,28 @@ function getStorageKey( : name; } +/** + * This is a special case of getStorageKey that should be used when dealing with + * read time resolver fields. A resolver may be used at both exec time and at read + * time within the same project. However, the value of the read time resolver is + * wrapped while the value of the exec time resolver is a standard Relay object. To + * disambiguate in the case that both types may exist on the same record, the read + * time resolver storage keys are prefixed. + */ +function getReadTimeResolverStorageKey( + field: + | ReaderRelayResolver + | ReaderRelayLiveResolver + | NormalizationResolverField + | NormalizationLiveResolverField, + variables: Variables, +): string { + const storageKey = getStorageKey(field, variables); + return RelayFeatureFlags.ENABLE_READ_TIME_RESOLVER_STORAGE_KEY_PREFIX + ? '$r:' + storageKey // Using inlined string to test the performance impact + : storageKey; +} + /** * Given a field the method returns an array of arguments. * For Relay resolver fields, we store arguments on the field and fragment @@ -271,12 +298,14 @@ const RelayStoreUtils = { RELAY_RESOLVER_SNAPSHOT_KEY: '__resolverSnapshot', RELAY_RESOLVER_ERROR_KEY: '__resolverError', RELAY_RESOLVER_OUTPUT_TYPE_RECORD_IDS: '__resolverOutputTypeRecordIDs', + RELAY_READ_TIME_RESOLVER_KEY_PREFIX, formatStorageKey, getArgumentValue, getArgumentValues, getHandleStorageKey, getStorageKey, + getReadTimeResolverStorageKey, getStableStorageKey, getModuleComponentKey, getModuleOperationKey, diff --git a/packages/relay-runtime/store/ResolverCache.js b/packages/relay-runtime/store/ResolverCache.js index 91b2b1101adc0..1d2f00243a957 100644 --- a/packages/relay-runtime/store/ResolverCache.js +++ b/packages/relay-runtime/store/ResolverCache.js @@ -18,7 +18,7 @@ import type { import type {DataID, Variables} from '../util/RelayRuntimeTypes'; import type { DataIDSet, - ErrorResponseFields, + FieldErrors, SingularReaderSelector, Snapshot, } from './RelayStoreTypes'; @@ -35,7 +35,7 @@ export type EvaluationResult = { export type ResolverFragmentResult = { data: mixed, isMissingData: boolean, - errorResponseFields: ?ErrorResponseFields, + fieldErrors: ?FieldErrors, }; export type GetDataForResolverFragmentFn = diff --git a/packages/relay-runtime/store/ResolverFragments.js b/packages/relay-runtime/store/ResolverFragments.js index 9e1256533f12b..a55c224314884 100644 --- a/packages/relay-runtime/store/ResolverFragments.js +++ b/packages/relay-runtime/store/ResolverFragments.js @@ -112,12 +112,14 @@ function readFragment( fragmentSelector.kind === 'SingularReaderSelector', `Expected a singular reader selector for the fragment of the resolver ${fragmentNode.name}, but it was plural.`, ); - const {data, isMissingData, errorResponseFields} = - context.getDataForResolverFragment(fragmentSelector, fragmentKey); + const {data, isMissingData, fieldErrors} = context.getDataForResolverFragment( + fragmentSelector, + fragmentKey, + ); if ( isMissingData || - (errorResponseFields != null && errorResponseFields.some(eventShouldThrow)) + (fieldErrors != null && fieldErrors.some(eventShouldThrow)) ) { throw RESOLVER_FRAGMENT_ERRORED_SENTINEL; } diff --git a/packages/relay-runtime/store/StoreInspector.js b/packages/relay-runtime/store/StoreInspector.js index 15ff2125feadf..6d96ba585b00a 100644 --- a/packages/relay-runtime/store/StoreInspector.js +++ b/packages/relay-runtime/store/StoreInspector.js @@ -32,11 +32,14 @@ if (__DEV__) { } formattersInstalled = true; // $FlowFixMe[incompatible-use] D61394600 + // $FlowFixMe[cannot-resolve-name] if (window.devtoolsFormatters == null) { // $FlowFixMe[incompatible-use] D61394600 + // $FlowFixMe[cannot-resolve-name] window.devtoolsFormatters = []; } // $FlowFixMe[incompatible-use] D61394600 + // $FlowFixMe[cannot-resolve-name] if (!Array.isArray(window.devtoolsFormatters)) { return; } @@ -47,6 +50,7 @@ if (__DEV__) { 'section.', ); // $FlowFixMe[incompatible-use] D61394600 + // $FlowFixMe[cannot-resolve-name] window.devtoolsFormatters.push(...createFormatters()); }; @@ -137,6 +141,7 @@ if (__DEV__) { ): ?{[string]: mixed} => { const record = source.get(dataID); if (record == null) { + // $FlowFixMe[incompatible-return] return record; } return new Proxy( diff --git a/packages/relay-runtime/store/__tests__/DataChecker-test.js b/packages/relay-runtime/store/__tests__/DataChecker-test.js index ee81e14ef22cb..88daab20c49da 100644 --- a/packages/relay-runtime/store/__tests__/DataChecker-test.js +++ b/packages/relay-runtime/store/__tests__/DataChecker-test.js @@ -257,6 +257,7 @@ describe('check()', () => { id: '1', __typename: 'User', 'profilePicture(size:32)': {__ref: 'client:1'}, + // $FlowFixMe[invalid-computed-prop] [handleKey]: {__ref: 'client:3'}, }, 'client:1': { @@ -348,6 +349,7 @@ describe('check()', () => { id: '1', __typename: 'User', 'profilePicture(size:32)': {__ref: 'client:1'}, + // $FlowFixMe[invalid-computed-prop] [handleKey]: {__ref: 'client:3'}, }, 'client:1': { @@ -399,6 +401,7 @@ describe('check()', () => { id: '1', __typename: 'User', 'profilePicture(size:32)': {__ref: 'client:1'}, + // $FlowFixMe[invalid-computed-prop] [handleKey]: {__ref: 'client:3'}, }, 'client:1': { @@ -517,6 +520,7 @@ describe('check()', () => { id: '1', __typename: 'User', 'profilePicture(size:32)': {__ref: 'client:1'}, + // $FlowFixMe[invalid-computed-prop] [handleKey]: {__ref: 'client:3'}, }, 'client:1': { @@ -581,6 +585,7 @@ describe('check()', () => { __id: 'client:2', __typename: 'Photo', uri: 'https://...', + // $FlowFixMe[invalid-computed-prop] [handleKey]: 'https://...', }, }; @@ -708,7 +713,7 @@ describe('check()', () => { BarQuery = graphql` query DataCheckerTest4Query($id: ID!) { node(id: $id) { - ...DataCheckerTest4Fragment + ...DataCheckerTest4Fragment @dangerously_unaliased_fixme } } `; @@ -1160,7 +1165,7 @@ describe('check()', () => { BarQuery = graphql` query DataCheckerTest5Query($id: ID!) { node(id: $id) { - ...DataCheckerTest5Fragment + ...DataCheckerTest5Fragment @dangerously_unaliased_fixme } } `; @@ -1512,7 +1517,9 @@ describe('check()', () => { Query = graphql` query DataCheckerTest9Query($id: ID!) { node(id: $id) { - ...DataCheckerTest6Fragment @defer(label: "TestFragment") + ...DataCheckerTest6Fragment + @dangerously_unaliased_fixme + @defer(label: "TestFragment") } } `; @@ -1604,7 +1611,7 @@ describe('check()', () => { Query = graphql` query DataCheckerTest6Query($id: ID!) { node(id: $id) { - ...DataCheckerTest7Fragment + ...DataCheckerTest7Fragment @dangerously_unaliased_fixme } } `; @@ -2648,6 +2655,7 @@ describe('check()', () => { name: 'Alice', // no `id` value }, + // $FlowFixMe[invalid-computed-prop] [typeID]: { __id: typeID, __typename: TYPE_SCHEMA_TYPE, @@ -2703,6 +2711,7 @@ describe('check()', () => { name: 'Alice', id: '1', }, + // $FlowFixMe[invalid-computed-prop] [typeID]: { __id: typeID, __typename: TYPE_SCHEMA_TYPE, @@ -2759,6 +2768,7 @@ describe('check()', () => { // no 'id' bc not a Node name: 'Not a Node!', }, + // $FlowFixMe[invalid-computed-prop] [typeID]: { __id: typeID, __typename: TYPE_SCHEMA_TYPE, @@ -2862,6 +2872,7 @@ describe('check()', () => { __typename: 'Text', text: 'Hello, Antonio', }, + // $FlowFixMe[invalid-computed-prop] [typeID]: { __id: typeID, __typename: TYPE_SCHEMA_TYPE, @@ -3055,4 +3066,160 @@ describe('check()', () => { ); expect(target.toJSON()).toEqual({}); }); + + describe('exec time resolvers', () => { + describe('client query', () => { + const Query = graphql` + query DataCheckerTestExecQuery @exec_time_resolvers { + RelayReaderExecResolversTest_user_one { + name + best_friend { + name + best_friend { + name + } + } + } + } + `; + + it('should return available when all data is available', () => { + const source = RelayRecordSource.create({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + RelayReaderExecResolversTest_user_one: {__ref: '1'}, + }, + '1': { + __id: '1', + name: 'Alice', + best_friend: {__ref: '2'}, + }, + '2': { + __id: '2', + name: 'Bob', + best_fried: {__ref: '3'}, + }, + '3': { + __id: '3', + name: 'Zuck', + }, + }); + const target = RelayRecordSource.create(); + const status = check( + () => source, + () => target, + INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE, + createNormalizationSelector(getRequest(Query).operation, ROOT_ID, {}), + [], + null, + defaultGetDataID, + ); + expect(status.status).toBe('available'); + }); + + it('should return available when only client data is missing', () => { + const source = RelayRecordSource.create({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + RelayReaderExecResolversTest_user_one: {__ref: '1'}, + }, + '1': { + __id: '1', + name: 'Alice', + best_friend: {__ref: '2'}, + }, + '2': { + __id: '2', + name: 'Bob', + best_fried: undefined, + }, + }); + const target = RelayRecordSource.create(); + const status = check( + () => source, + () => target, + INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE, + createNormalizationSelector(getRequest(Query).operation, ROOT_ID, {}), + [], + null, + defaultGetDataID, + ); + expect(status.status).toBe('available'); + }); + }); + + describe('server and client query', () => { + const Query = graphql` + query DataCheckerTestExecWithServerDataQuery @exec_time_resolvers { + RelayReaderExecResolversTest_user_one { + name + best_friend { + name + best_friend { + name + } + } + } + me { + name + } + } + `; + it('should return available when server data is available', () => { + const source = RelayRecordSource.create({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + RelayReaderExecResolversTest_user_one: undefined, + me: {__ref: '0'}, + }, + '0': { + __id: '0', + id: '0', + name: 'Zuck', + }, + }); + const target = RelayRecordSource.create(); + const status = check( + () => source, + () => target, + INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE, + createNormalizationSelector(getRequest(Query).operation, ROOT_ID, {}), + [], + null, + defaultGetDataID, + ); + expect(status.status).toBe('available'); + }); + + it('should return missing when server data is missing', () => { + const source = RelayRecordSource.create({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + RelayReaderExecResolversTest_user_one: undefined, + me: {__ref: '0'}, + }, + '0': { + __id: '0', + id: '0', + name: undefined, + }, + }); + const target = RelayRecordSource.create(); + const status = check( + () => source, + () => target, + INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE, + createNormalizationSelector(getRequest(Query).operation, ROOT_ID, {}), + [], + null, + defaultGetDataID, + ); + expect(status.status).toBe('missing'); + }); + }); + }); }); diff --git a/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseHandler-test.js b/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseHandler-test.js index 5d4a4ba41eadc..5fc33667000d8 100644 --- a/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseHandler-test.js +++ b/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseHandler-test.js @@ -30,6 +30,7 @@ const {getRequest} = require('relay-runtime/query/GraphQLTag'); const defaultOptions = { getDataID: defaultGetDataID, treatMissingFieldsAsNull: false, + log: null, }; function applyTransform( diff --git a/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseTransform-test.js b/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseTransform-test.js index 43bff654705e3..eb4247937d0ca 100644 --- a/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseTransform-test.js +++ b/packages/relay-runtime/store/__tests__/RelayExperimentalGraphResponseTransform-test.js @@ -32,6 +32,7 @@ const {ROOT_ID} = require('relay-runtime/store/RelayStoreUtils'); const defaultOptions = { getDataID: defaultGetDataID, treatMissingFieldsAsNull: false, + log: null, }; function applyTransform( @@ -588,6 +589,7 @@ test('Fragment Spread (gets inlined into `InlineFragment`)', () => { query RelayExperimentalGraphResponseTransformTestFragmentSpreadQuery { node(id: "10") { ...RelayExperimentalGraphResponseTransformTest_user_name + @dangerously_unaliased_fixme } } `; @@ -644,6 +646,7 @@ test('Fragment Spread @no_inline', () => { query RelayExperimentalGraphResponseTransformTestFragmentSpreadNoInlineQuery { node(id: "10") { ...RelayExperimentalGraphResponseTransformTest_no_inline_user_name + @dangerously_unaliased_fixme } } `; @@ -702,6 +705,7 @@ test('Traverses when @defer is disabled', () => { ) { node(id: $id) { ...RelayExperimentalGraphResponseTransformTest_condition + @dangerously_unaliased_fixme @defer(label: "TestFragment", if: $enableDefer) } } diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ApplyMutation-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ApplyMutation-test.js index dfb6f0229ef2c..af46400e6560d 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ApplyMutation-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ApplyMutation-test.js @@ -90,6 +90,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( node(id: $id) { id ...RelayModernEnvironmentApplyMutationTestFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-Connection-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-Connection-test.js index dcb96cd423de7..e61d9983f0464 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-Connection-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-Connection-test.js @@ -57,6 +57,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( query RelayModernEnvironmentConnectionTestFeedbackQuery($id: ID!) { node(id: $id) { ...RelayModernEnvironmentConnectionTestFeedbackFragment + @dangerously_unaliased_fixme } } `; @@ -68,6 +69,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( ) { node(id: $id) { ...RelayModernEnvironmentConnectionTestFeedbackFragment + @dangerously_unaliased_fixme @arguments(count: $count, cursor: $cursor) } } diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ConnectionAndRequired-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ConnectionAndRequired-test.js index d1a8a0664ed64..4cd1e6e23c4ad 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ConnectionAndRequired-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ConnectionAndRequired-test.js @@ -50,6 +50,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( ) { node(id: $id) { ...RelayModernEnvironmentConnectionAndRequiredTestFeedbackFragment + @dangerously_unaliased_fixme } } `; @@ -130,7 +131,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( getSingularSelector(fragment, nextOperationSnapshot.data?.node), ); const snapshot = environment.lookup(selector); - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { kind: 'missing_required_field.log', owner: diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-DynamicConnectionKey-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-DynamicConnectionKey-test.js index c230bdddb83a5..53d607e69dbce 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-DynamicConnectionKey-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-DynamicConnectionKey-test.js @@ -61,6 +61,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( ) { node(id: $id) { ...RelayModernEnvironmentDynamicConnectionKeyTestFeedbackFragment + @dangerously_unaliased_fixme } } `; @@ -73,6 +74,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( ) { node(id: $id) { ...RelayModernEnvironmentDynamicConnectionKeyTestFeedbackFragment + @dangerously_unaliased_fixme @arguments(count: $count, cursor: $cursor) } } diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-WithLocalInvalidation-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-WithLocalInvalidation-test.js index 92756c69ac7ba..1f1ad481a0336 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-WithLocalInvalidation-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-WithLocalInvalidation-test.js @@ -85,6 +85,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( node(id: $id) { id ...RelayModernEnvironmentExecuteMutationWithLocalInvalidationTestCommentFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-test.js index ea8e3be40d71c..9dab1564ec33a 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutation-test.js @@ -105,6 +105,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( node(id: $id) { id ...RelayModernEnvironmentExecuteMutationTestCommentFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithGlobalInvalidation-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithGlobalInvalidation-test.js index 4cec04d91125e..829416d42c55e 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithGlobalInvalidation-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithGlobalInvalidation-test.js @@ -87,6 +87,7 @@ describe('executeMutation() with global invalidation', () => { node(id: $id) { id ...RelayModernEnvironmentExecuteMutationWithGlobalInvalidationTestCommentFragment + @dangerously_unaliased_fixme } } `, diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithMatch-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithMatch-test.js index 658456ce3ed17..2d2fe0ba6f7b7 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithMatch-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithMatch-test.js @@ -145,6 +145,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( node(id: $id) { id ...RelayModernEnvironmentExecuteMutationWithMatchTestCommentFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscription-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscription-test.js index c7e8ef8977deb..60cf788d7fb1f 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscription-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscription-test.js @@ -75,6 +75,7 @@ describe('execute()', () => { node(id: $id) { id ...RelayModernEnvironmentExecuteSubscriptionTestCommentFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithDefer-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithDefer-test.js index 922b32ebc597f..847d19e2cb0b5 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithDefer-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithDefer-test.js @@ -88,6 +88,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( node(id: $id) { id ...RelayModernEnvironmentExecuteSubscriptionWithDeferTestCommentFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithMatch-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithMatch-test.js index 3745e3bdd58ff..b3470e4814e98 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithMatch-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithMatch-test.js @@ -144,6 +144,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( node(id: $id) { id ...RelayModernEnvironmentExecuteSubscriptionWithMatchTestCommentFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithStream-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithStream-test.js index 33b767cc4b854..de51793b1f354 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithStream-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteSubscriptionWithStream-test.js @@ -81,6 +81,7 @@ describe('executeSubscrption() with @stream', () => { node(id: $id) { id ...RelayModernEnvironmentExecuteSubscriptionWithStreamTestFeedbackFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithCheck-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithCheck-test.js new file mode 100644 index 0000000000000..9526d7fb1b4ea --- /dev/null +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithCheck-test.js @@ -0,0 +1,97 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall relay + */ + +'use strict'; +import type {GraphQLResponse} from '../../network/RelayNetworkTypes'; + +const RelayObservable = require('../../network/RelayObservable'); +const {graphql} = require('../../query/GraphQLTag'); +const RelayModernEnvironment = require('../RelayModernEnvironment'); +const { + createOperationDescriptor, +} = require('../RelayModernOperationDescriptor'); +const RelayModernStore = require('../RelayModernStore'); +const RelayRecordSource = require('../RelayRecordSource'); +const {disallowWarnings} = require('relay-test-utils-internal'); + +disallowWarnings(); + +describe('execute() provides a `check` function for the network layer to determine availability of data in store', () => { + let callbacks; + let complete; + let environment; + let error; + let next; + let operation; + let query; + let source; + let store; + let subject; + let variables; + let network; + let check; + beforeEach(() => { + query = graphql` + query RelayModernEnvironmentExecuteWithCheckTestQuery( + $fetchSize: Boolean! + ) { + me { + name + profilePicture(size: 42) @include(if: $fetchSize) { + uri + } + } + } + `; + variables = {fetchSize: false}; + operation = createOperationDescriptor(query, variables); + + complete = jest.fn<[], mixed>(); + error = jest.fn<[Error], mixed>(); + next = jest.fn<[GraphQLResponse], mixed>(); + callbacks = {complete, error, next}; + + network = { + execute: jest.fn( + (_query, _variables, _cacheConfig, _1, _2, _3, _4, _check) => { + check = _check; + return RelayObservable.create(sink => { + subject = sink; + }); + }, + ), + }; + source = RelayRecordSource.create(); + store = new RelayModernStore(source); + environment = new RelayModernEnvironment({ + network, + store, + }); + }); + + it('returns the correct availability in the check function', () => { + environment.execute({operation}).subscribe(callbacks); + expect(check().status).toBe('missing'); + subject.next({ + data: { + me: { + id: '842472', + __typename: 'User', + name: 'Joe', + }, + }, + }); + jest.runAllTimers(); + + environment.execute({operation}).subscribe(callbacks); + expect(check().status).toBe('available'); + }); +}); diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithDefer-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithDefer-test.js index 90bbd3c1f1c9b..7ea7ba9d61b39 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithDefer-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithDefer-test.js @@ -67,6 +67,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( query RelayModernEnvironmentExecuteWithDeferTestUserQuery($id: ID!) { node(id: $id) { ...RelayModernEnvironmentExecuteWithDeferTestUserFragment + @dangerously_unaliased_fixme @defer(label: "UserFragment") } } diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithOverlappingStream-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithOverlappingStream-test.js index 28fd36854d482..f28ee0b2ff18c 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithOverlappingStream-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithOverlappingStream-test.js @@ -65,6 +65,7 @@ describe('execute() a query with multiple @stream selections on the same record' ) { node(id: $id) { ...RelayModernEnvironmentExecuteWithOverlappingStreamTestFeedbackFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithProvidedVariable-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithProvidedVariable-test.js index 03468c2e5453a..c5d3e448eb30f 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithProvidedVariable-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithProvidedVariable-test.js @@ -118,6 +118,7 @@ describe('query with fragments that use provided variables', () => { ) { node(id: $id) { ...RelayModernEnvironmentExecuteWithProvidedVariableTest_profile1 + @dangerously_unaliased_fixme } } `; @@ -128,8 +129,11 @@ describe('query with fragments that use provided variables', () => { ) { node(id: $id) { ...RelayModernEnvironmentExecuteWithProvidedVariableTest_profile1 + @dangerously_unaliased_fixme ...RelayModernEnvironmentExecuteWithProvidedVariableTest_profile2 + @dangerously_unaliased_fixme ...RelayModernEnvironmentExecuteWithProvidedVariableTest_profile3 + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStream-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStream-test.js index 27b23668b6c9a..bd0f65dc6e72d 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStream-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStream-test.js @@ -62,6 +62,7 @@ describe('execute() a query with @stream', () => { ) { node(id: $id) { ...RelayModernEnvironmentExecuteWithStreamTestFeedbackFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamAndRequired-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamAndRequired-test.js index 52b81726d03d9..cc82b36b59d44 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamAndRequired-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamAndRequired-test.js @@ -50,6 +50,7 @@ describe('execute() a query with @stream and @required', () => { ) { node(id: $id) { ...RelayModernEnvironmentExecuteWithStreamAndRequiredTestFeedbackFragment + @dangerously_unaliased_fixme } } `; @@ -111,7 +112,7 @@ describe('execute() a query with @stream and @required', () => { jest.runAllTimers(); const snapshot = callback.mock.calls[0][0]; - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { kind: 'missing_required_field.log', owner: diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamWithHandler-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamWithHandler-test.js index a485d0b6270b2..294880d3f8d40 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamWithHandler-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithStreamWithHandler-test.js @@ -61,6 +61,7 @@ describe('execute() a query with @stream with handler', () => { ) { node(id: $id) { ...RelayModernEnvironmentExecuteWithStreamWithHandlerTestFeedbackFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithUndeclaredUnusedArgument-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithUndeclaredUnusedArgument-test.js index 13db879a0a3ca..6f53dc602d1b2 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithUndeclaredUnusedArgument-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithUndeclaredUnusedArgument-test.js @@ -46,6 +46,7 @@ describe('query with undeclared, unused fragment argument', () => { ) { node(id: $id) { ...RelayModernEnvironmentExecuteWithUndeclaredUnusedArgumentTestProfile + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-NoInline-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-NoInline-test.js index a545ec7d81de9..87a5a92dbf74c 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-NoInline-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-NoInline-test.js @@ -64,6 +64,7 @@ const NoInlineFragment = graphql` } } ...RelayModernEnvironmentNoInlineTest_inner + @dangerously_unaliased_fixme @arguments(cond: true, preset: $preset, fileExtension: JPG) } `; @@ -373,6 +374,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( } } ...RelayModernEnvironmentNoInlineTest_inner + @dangerously_unaliased_fixme @arguments( cond: $cond preset: $preset @@ -542,14 +544,17 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( @argumentDefinitions(cond: {type: "Boolean!"}) { mark: username(name: "Mark") { ...RelayModernEnvironmentNoInlineTest_nestedNoInline + @dangerously_unaliased_fixme @arguments(cond: $global_cond) } zuck: username(name: "Zuck") { ...RelayModernEnvironmentNoInlineTest_nestedNoInline + @dangerously_unaliased_fixme @arguments(cond: false) } joe: username(name: "Joe") { ...RelayModernEnvironmentNoInlineTest_nestedNoInline + @dangerously_unaliased_fixme @arguments(cond: $cond) } } @@ -703,6 +708,7 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])( ) { node(id: "1") { ...RelayModernEnvironmentNoInlineTestStream_feedback + @dangerously_unaliased_fixme @arguments(cond: $cond) } } diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-SubscriptionWithResolverContext-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-SubscriptionWithResolverContext-test.js new file mode 100644 index 0000000000000..a2a2b7fbc29fe --- /dev/null +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-SubscriptionWithResolverContext-test.js @@ -0,0 +1,94 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall relay + */ + +'use strict'; +import type {Snapshot} from '../RelayStoreTypes'; +import type {RecordSourceProxy} from 'relay-runtime/store/RelayStoreTypes'; + +const RelayNetwork = require('../../network/RelayNetwork'); +const {graphql} = require('../../query/GraphQLTag'); +const RelayModernEnvironment = require('../RelayModernEnvironment'); +const { + createOperationDescriptor, +} = require('../RelayModernOperationDescriptor'); +const {createReaderSelector} = require('../RelayModernSelector'); +const RelayModernStore = require('../RelayModernStore'); +const RelayRecordSource = require('../RelayRecordSource'); +const {disallowWarnings} = require('relay-test-utils-internal'); + +disallowWarnings(); + +describe('RelayContext works when applying updates and gets passed through to the RelayStoreSubscriptions', () => { + it('correctly using the resolver data from the context', () => { + const ParentQuery = graphql` + query RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery { + me { + ...RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment + } + } + `; + const UserFragment = graphql` + fragment RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment on User { + id + name + age + } + `; + + const source = RelayRecordSource.create(); + const store = new RelayModernStore(source, { + resolverContext: { + age: 42, + }, + }); + const environment = new RelayModernEnvironment({ + network: RelayNetwork.create(jest.fn()), + store, + }); + const operation = createOperationDescriptor(ParentQuery, {}); + + const selector = createReaderSelector( + UserFragment, + '4', + {}, + operation.request, + ); + const callback = jest.fn<[Snapshot], void>(); + const snapshot = environment.lookup(selector); + environment.subscribe(snapshot, callback); + + callback.mockClear(); + const updater = { + storeUpdater: (proxyStore: RecordSourceProxy) => { + const zuck = proxyStore.create('4', 'User'); + zuck.setValue('4', 'id'); + }, + }; + environment.applyUpdate(updater); + environment.replaceUpdate(updater, { + storeUpdater: proxyStore => { + const zuck = proxyStore.create('4', 'User'); + zuck.setValue('4', 'id'); + zuck.setValue('zuck', 'name'); + }, + }); + expect(callback.mock.calls.length).toBe(2); + expect(callback.mock.calls[0][0].data).toEqual({ + id: '4', + age: 42, + }); + expect(callback.mock.calls[1][0].data).toEqual({ + id: '4', + name: 'zuck', + age: 42, + }); + }); +}); diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-TypeRefinement-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-TypeRefinement-test.js index 29deb890686c7..e90cb2d123362 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-TypeRefinement-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-TypeRefinement-test.js @@ -109,9 +109,13 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTestParentQuery { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTestConcreteUserFragment + @dangerously_unaliased_fixme ...RelayModernEnvironmentTypeRefinementTestConcreteInlineRefinementFragment + @dangerously_unaliased_fixme ...RelayModernEnvironmentTypeRefinementTestAbstractActorFragment + @dangerously_unaliased_fixme ...RelayModernEnvironmentTypeRefinementTestAbstractInlineRefinementFragment + @dangerously_unaliased_fixme } } `; @@ -121,7 +125,9 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTestConcreteQuery { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTestConcreteUserFragment + @dangerously_unaliased_fixme ...RelayModernEnvironmentTypeRefinementTestConcreteInlineRefinementFragment + @dangerously_unaliased_fixme } } `; @@ -131,7 +137,9 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTestAbstractQuery { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTestAbstractActorFragment + @dangerously_unaliased_fixme ...RelayModernEnvironmentTypeRefinementTestAbstractInlineRefinementFragment + @dangerously_unaliased_fixme } } `; @@ -1021,6 +1029,7 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTest2Query { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTest3Fragment + @dangerously_unaliased_fixme } } `; @@ -1237,6 +1246,7 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTest3Query { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTest5Fragment + @dangerously_unaliased_fixme } } `; @@ -1245,6 +1255,7 @@ describe('missing data detection', () => { id lastName ...RelayModernEnvironmentTypeRefinementTest6Fragment + @dangerously_unaliased_fixme } `; NestedNamedFragment = graphql` @@ -1456,6 +1467,7 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTest4Query { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTest7Fragment + @dangerously_unaliased_fixme } } `; @@ -1677,6 +1689,7 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTest5Query { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTest9Fragment + @dangerously_unaliased_fixme } } `; @@ -1685,6 +1698,7 @@ describe('missing data detection', () => { id lastName ...RelayModernEnvironmentTypeRefinementTest10Fragment + @dangerously_unaliased_fixme } `; NestedUserFragment = graphql` @@ -1794,6 +1808,7 @@ describe('missing data detection', () => { query RelayModernEnvironmentTypeRefinementTest6Query { userOrPage(id: "abc") { ...RelayModernEnvironmentTypeRefinementTest11Fragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-WithOperationTracker-test.js b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-WithOperationTracker-test.js index 7242a46e5d046..105f91f366260 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernEnvironment-WithOperationTracker-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernEnvironment-WithOperationTracker-test.js @@ -502,6 +502,7 @@ describe.each([true, false])( @relay_test_operation { node(id: $id) { ...RelayModernEnvironmentWithOperationTrackerTestFeedbackFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-WithFragmentOwnership-test.js b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-WithFragmentOwnership-test.js index 6a450e4a3c0c6..73f49dce3ec35 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-WithFragmentOwnership-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-WithFragmentOwnership-test.js @@ -98,7 +98,9 @@ describe('RelayModernFragmentSpecResolver with fragment ownership', () => { ) { node(id: $id) { ...RelayModernFragmentSpecResolverWithFragmentOwnershipTestUserFragment + @dangerously_unaliased_fixme ...RelayModernFragmentSpecResolverWithFragmentOwnershipTestUsersFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-test.js b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-test.js index b32ebcc1bc576..06823d39ef1a7 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolver-test.js @@ -83,7 +83,9 @@ describe('RelayModernFragmentSpecResolver', () => { ) { node(id: $id) { ...RelayModernFragmentSpecResolverTestQueryUserFragment + @dangerously_unaliased_fixme ...RelayModernFragmentSpecResolverTestQueryUsersFragment + @dangerously_unaliased_fixme } } `; @@ -874,7 +876,9 @@ describe('RelayModernFragmentSpecResolver', () => { ) { node(id: $id) { ...RelayModernFragmentSpecResolverTestQueryUserFragment + @dangerously_unaliased_fixme ...RelayModernFragmentSpecResolverTestQueryUsersFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredField-test.js b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredField-test.js index 9825403c150d4..d9ac965460f19 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredField-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredField-test.js @@ -54,6 +54,7 @@ describe('RelayModernFragmentSpecResolver', () => { ) { node(id: $id) { ...RelayModernFragmentSpecResolverRequiredFieldTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredFieldNoLogger-test.js b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredFieldNoLogger-test.js index d6afca959519d..8f8f21a358ca2 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredFieldNoLogger-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernFragmentSpecResolverRequiredFieldNoLogger-test.js @@ -55,6 +55,7 @@ describe('RelayModernFragmentSpecResolver', () => { ) { node(id: $id) { ...RelayModernFragmentSpecResolverRequiredFieldNoLoggerTestUserFragment + @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernSelector-test.js b/packages/relay-runtime/store/__tests__/RelayModernSelector-test.js index e6dfe61fc4981..8876fe69fffee 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernSelector-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernSelector-test.js @@ -56,8 +56,8 @@ describe('RelayModernSelector', () => { $cond: Boolean! ) { node(id: $id) { - ...RelayModernSelectorTestUserFragment - ...RelayModernSelectorTestUsersFragment + ...RelayModernSelectorTestUserFragment @dangerously_unaliased_fixme + ...RelayModernSelectorTestUsersFragment @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayModernStore-Subscriptions-test.js b/packages/relay-runtime/store/__tests__/RelayModernStore-Subscriptions-test.js index 67f27036848b8..ee54a39cbc2db 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernStore-Subscriptions-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernStore-Subscriptions-test.js @@ -371,7 +371,7 @@ function cloneEventWithSets(event: LogEvent) { ...snapshot, missingLiveResolverFields: [], isMissingData: false, - errorResponseFields: null, + fieldErrors: null, data: { name: 'Zuck', profilePicture: { @@ -415,7 +415,7 @@ function cloneEventWithSets(event: LogEvent) { }, missingLiveResolverFields: [], isMissingData: true, - errorResponseFields: [ + fieldErrors: [ { fieldPath: 'profilePicture', kind: 'missing_expected_data.log', @@ -464,7 +464,7 @@ function cloneEventWithSets(event: LogEvent) { name: 'Joe', profilePicture: undefined, }, - errorResponseFields: [ + fieldErrors: [ { fieldPath: 'profilePicture', kind: 'missing_expected_data.log', diff --git a/packages/relay-runtime/store/__tests__/RelayModernStore-test.js b/packages/relay-runtime/store/__tests__/RelayModernStore-test.js index 2ef5803e28304..9a8ec497ac5dd 100644 --- a/packages/relay-runtime/store/__tests__/RelayModernStore-test.js +++ b/packages/relay-runtime/store/__tests__/RelayModernStore-test.js @@ -103,7 +103,9 @@ function cloneEventWithSets(event: LogEvent) { describe('constructor', () => { it('creates the root record upon store initialization', () => { const source = getRecordSourceImplementation({}); - const store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + const store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + }); expect(store.getSource().get(ROOT_ID)).toEqual({ __id: ROOT_ID, __typename: ROOT_TYPE, @@ -145,11 +147,14 @@ function cloneEventWithSets(event: LogEvent) { }; initialData = simpleClone(data); source = getRecordSourceImplementation(data); - store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + queryCacheExpirationTime: 0, + }); UserQuery = graphql` query RelayModernStoreTest1Query($id: ID!, $size: [Int]) { node(id: $id) { - ...RelayModernStoreTest1Fragment + ...RelayModernStoreTest1Fragment @dangerously_unaliased_fixme } } `; @@ -252,7 +257,9 @@ function cloneEventWithSets(event: LogEvent) { }, }; source = getRecordSourceImplementation(data); - store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + }); UserFragment = graphql` fragment RelayModernStoreTest2Fragment on User { name @@ -288,7 +295,7 @@ function cloneEventWithSets(event: LogEvent) { }, }, seenRecords: new Set(Object.keys(data)), - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, @@ -341,7 +348,7 @@ function cloneEventWithSets(event: LogEvent) { __fragmentOwner: owner.request, }, seenRecords: new Set(Object.keys(data)), - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, @@ -398,7 +405,7 @@ function cloneEventWithSets(event: LogEvent) { }, }, seenRecords: new Set(['client:2', '4']), - errorResponseFields: null, + fieldErrors: null, missingLiveResolverFields: [], missingClientEdges: null, isMissingData: false, @@ -448,6 +455,7 @@ function cloneEventWithSets(event: LogEvent) { >); source = getRecordSourceImplementation(data); store = new RelayModernStore(source, { + shouldRetainWithinTTL_EXPERIMENTAL: true, log: event => { logEvents.push(cloneEventWithSets(event)); }, @@ -654,7 +662,10 @@ function cloneEventWithSets(event: LogEvent) { }, }; source = getRecordSourceImplementation(dataObj); - store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + shouldRetainWithinTTL_EXPERIMENTAL: true, + }); const owner = createOperationDescriptor(UserQuery, {}); const selector = createReaderSelector( UserFragment, @@ -682,7 +693,7 @@ function cloneEventWithSets(event: LogEvent) { ...snapshot, missingClientEdges: null, isMissingData: false, - errorResponseFields: null, + fieldErrors: null, data: { name: 'Zuck', profilePicture: { @@ -724,7 +735,7 @@ function cloneEventWithSets(event: LogEvent) { name: 'Joe', profilePicture: undefined, }, - errorResponseFields: [ + fieldErrors: [ { owner: 'RelayModernStoreTest5Fragment', kind: 'missing_expected_data.log', @@ -778,7 +789,7 @@ function cloneEventWithSets(event: LogEvent) { }, missingClientEdges: null, isMissingData: true, - errorResponseFields: [ + fieldErrors: [ { owner: 'RelayModernStoreTest5Fragment', kind: 'missing_expected_data.log', @@ -1184,11 +1195,14 @@ function cloneEventWithSets(event: LogEvent) { }, }; source = getRecordSourceImplementation(data); - store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + shouldRetainWithinTTL_EXPERIMENTAL: true, + }); UserQuery = graphql` query RelayModernStoreTest6Query($id: ID!, $size: [Int]) { node(id: $id) { - ...RelayModernStoreTest7Fragment + ...RelayModernStoreTest7Fragment @dangerously_unaliased_fixme } } `; @@ -1242,7 +1256,10 @@ function cloneEventWithSets(event: LogEvent) { // $FlowFixMe[incompatible-type] found deploying v0.109.0 delete data['client:1']; // profile picture source = getRecordSourceImplementation(data); - store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + shouldRetainWithinTTL_EXPERIMENTAL: true, + }); const operation = createOperationDescriptor(UserQuery, { id: '4', size: 32, @@ -1265,6 +1282,7 @@ function cloneEventWithSets(event: LogEvent) { jest.spyOn(global.Date, 'now').mockImplementation(() => currentTime); store = new RelayModernStore(source, { + shouldRetainWithinTTL_EXPERIMENTAL: true, queryCacheExpirationTime: QUERY_CACHE_EXPIRATION_TIME, gcReleaseBufferSize: 0, }); @@ -1291,6 +1309,39 @@ function cloneEventWithSets(event: LogEvent) { }); }); + describe('with infinite queryCacheExpirationTime', () => { + it('always returns available', () => { + let currentTime = Date.now(); + jest.spyOn(global.Date, 'now').mockImplementation(() => currentTime); + + store = new RelayModernStore(source, { + shouldRetainWithinTTL_EXPERIMENTAL: true, + queryCacheExpirationTime: null, + gcReleaseBufferSize: 0, + }); + const operation = createOperationDescriptor(UserQuery, { + id: '4', + size: 32, + }); + store.retain(operation); + store.publish(source); + store.notify(operation); + + expect(store.check(operation)).toEqual({ + status: 'available', + fetchTime: currentTime, + }); + + const fetchTime = currentTime; + currentTime += 10000; // arbitrary number + + expect(store.check(operation)).toEqual({ + status: 'available', + fetchTime, + }); + }); + }); + describe('with global store invalidation', () => { describe("when query hasn't been written to the store before", () => { it('returns stale if data is cached and store has been invalidated', () => { @@ -1383,6 +1434,7 @@ function cloneEventWithSets(event: LogEvent) { it('returns available if data is cached and store was invalidated before query was written (query not retained)', () => { store = new RelayModernStore(source, { + shouldRetainWithinTTL_EXPERIMENTAL: true, gcReleaseBufferSize: 1, }); environment = createMockEnvironment({store}); @@ -1640,7 +1692,10 @@ function cloneEventWithSets(event: LogEvent) { }, }; source = getRecordSourceImplementation(data); - store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + shouldRetainWithinTTL_EXPERIMENTAL: true, + }); environment = createMockEnvironment({store}); }); @@ -2070,13 +2125,14 @@ function cloneEventWithSets(event: LogEvent) { initialData = simpleClone(data); source = getRecordSourceImplementation(data); store = new RelayModernStore(source, { + shouldRetainWithinTTL_EXPERIMENTAL: true, gcReleaseBufferSize: 1, queryCacheExpirationTime: QUERY_CACHE_EXPIRATION_TIME, }); UserQuery = graphql` query RelayModernStoreTest7Query($id: ID!, $size: [Int]) { node(id: $id) { - ...RelayModernStoreTest8Fragment + ...RelayModernStoreTest8Fragment @dangerously_unaliased_fixme } } `; @@ -2173,6 +2229,9 @@ function cloneEventWithSets(event: LogEvent) { }); it('releases the operation and collects data after release buffer reaches capacity', () => { + let fetchTime = Date.now(); + jest.spyOn(global.Date, 'now').mockImplementation(() => fetchTime); + const disposable = store.retain( createOperationDescriptor(UserQuery, {id: '4', size: 32}), ); @@ -2195,6 +2254,10 @@ function cloneEventWithSets(event: LogEvent) { // Releasing second operation should cause release buffer to // go over capacity disposable2.dispose(); + + // TTL for all operations has passed + fetchTime += QUERY_CACHE_EXPIRATION_TIME; + jest.runAllTimers(); // Assert that the data for the first operation is collected, while // data for second operation is still retained via the release buffer @@ -2220,6 +2283,9 @@ function cloneEventWithSets(event: LogEvent) { }); it('when same operation retained multiple times, data is only collected until fully released from buffer', () => { + let fetchTime = Date.now(); + jest.spyOn(global.Date, 'now').mockImplementation(() => fetchTime); + const disposable = store.retain( createOperationDescriptor(UserQuery, {id: '4', size: 32}), ); @@ -2255,6 +2321,10 @@ function cloneEventWithSets(event: LogEvent) { // Releasing different operation should cause release buffer to // go over capacity disposable3.dispose(); + + // TTL for all operations has passed + fetchTime += QUERY_CACHE_EXPIRATION_TIME; + jest.runAllTimers(); // Assert that the data for the first operation is collected, while // data for secont operation is still retained via the release buffer @@ -2282,7 +2352,10 @@ function cloneEventWithSets(event: LogEvent) { it('does not free data if previously disposed query is retained again', () => { // Disposing and re-retaining an operation should cause that query to *not* count // toward the release buffer capacity. - store = new RelayModernStore(source, {gcReleaseBufferSize: 2}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 2, + shouldRetainWithinTTL_EXPERIMENTAL: true, + }); const operation1 = createOperationDescriptor(UserQuery, { id: '1', size: 32, @@ -2363,6 +2436,7 @@ function cloneEventWithSets(event: LogEvent) { [ROOT_ID]: { __id: ROOT_ID, __typename: ROOT_TYPE, + // $FlowFixMe[invalid-computed-prop] [`node(id:"${nodeID}")`]: {__ref: nodeID}, }, }); @@ -2378,6 +2452,7 @@ function cloneEventWithSets(event: LogEvent) { store = new RelayModernStore(source, { gcScheduler: mockScheduler, gcReleaseBufferSize: 0, + queryCacheExpirationTime: 0, }); }); @@ -2513,11 +2588,14 @@ function cloneEventWithSets(event: LogEvent) { }; initialData = simpleClone(data); source = getRecordSourceImplementation(data); - store = new RelayModernStore(source, {gcReleaseBufferSize: 0}); + store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + queryCacheExpirationTime: 0, + }); UserQuery = graphql` query RelayModernStoreTest9Query($id: ID!, $size: [Int]) { node(id: $id) { - ...RelayModernStoreTest9Fragment + ...RelayModernStoreTest9Fragment @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayReader-AliasedFragments-test.js b/packages/relay-runtime/store/__tests__/RelayReader-AliasedFragments-test.js index 6395068654d58..a8deb79f329e0 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-AliasedFragments-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-AliasedFragments-test.js @@ -906,8 +906,8 @@ describe('Inline Fragments', () => { `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); const snapshot = read(source, operation.fragment); - const {data, isMissingData, errorResponseFields} = snapshot; - expect(errorResponseFields).toBe(null); + const {data, isMissingData, fieldErrors} = snapshot; + expect(fieldErrors).toBe(null); expect(isMissingData).toBe(false); expect(data).toEqual({ node: { @@ -1035,11 +1035,8 @@ describe('Inline Fragments', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, isMissingData, errorResponseFields} = read( - source, - operation.fragment, - ); - expect(errorResponseFields).toEqual([ + const {data, isMissingData, fieldErrors} = read(source, operation.fragment); + expect(fieldErrors).toEqual([ { fieldPath: 'node.aliased_fragment.name', kind: 'missing_expected_data.log', @@ -1095,11 +1092,8 @@ describe('Inline Fragments', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, isMissingData, errorResponseFields} = read( - source, - operation.fragment, - ); - expect(errorResponseFields).toEqual([ + const {data, isMissingData, fieldErrors} = read(source, operation.fragment); + expect(fieldErrors).toEqual([ { fieldPath: 'node.aliased_fragment.', kind: 'missing_expected_data.log', diff --git a/packages/relay-runtime/store/__tests__/RelayReader-CatchFields-test.js b/packages/relay-runtime/store/__tests__/RelayReader-CatchFields-test.js index 2ec131d0ccde0..1e01dbc783e26 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-CatchFields-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-CatchFields-test.js @@ -41,8 +41,8 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); - expect(errorResponseFields).toEqual(null); + const {data, fieldErrors} = read(source, operation.fragment); + expect(fieldErrors).toEqual(null); expect(data).toEqual({me: {lastName: null}}); }); @@ -77,7 +77,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: { lastName: { @@ -91,7 +91,7 @@ describe('RelayReader @catch', () => { }, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { error: {message: 'There was an error!', path: ['me', 'lastName']}, fieldPath: 'me.lastName', @@ -136,7 +136,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: { lastName: null, @@ -147,7 +147,7 @@ describe('RelayReader @catch', () => { }, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.lastName', error: { @@ -191,7 +191,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ alsoMe: null, me: { @@ -205,7 +205,7 @@ describe('RelayReader @catch', () => { }, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { kind: 'missing_required_field.log', fieldPath: 'alsoMe.lastName', @@ -243,12 +243,12 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: null, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.firstName', handled: true, @@ -281,17 +281,14 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {data, fieldErrors, isMissingData} = read(source, operation.fragment); expect(data).toEqual({me: null}); // We still need to ensure that we will suspend if there is a request in flight. expect(isMissingData).toEqual(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.firstName', kind: 'missing_expected_data.log', @@ -324,17 +321,14 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {}); - const {data, errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {data, fieldErrors, isMissingData} = read(source, operation.fragment); expect(data).toEqual(null); // We still need to ensure that we will suspend if there is a request in flight. expect(isMissingData).toEqual(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.firstName', kind: 'missing_expected_data.log', @@ -367,17 +361,14 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {}); - const {data, errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {data, fieldErrors, isMissingData} = read(source, operation.fragment); expect(data).toEqual({errors: [{path: ['me', 'firstName']}], ok: false}); // We still need to ensure that we will suspend if there is a request in flight. expect(isMissingData).toEqual(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.firstName', kind: 'missing_expected_data.log', @@ -417,7 +408,7 @@ describe('RelayReader @catch', () => { `; const owner = createOperationDescriptor(FooQuery, {}); - const {data, errorResponseFields, isMissingData} = read( + const {data, fieldErrors, isMissingData} = read( source, createReaderSelector(FooFragment, 'client:root', {}, owner.request), ); @@ -427,7 +418,7 @@ describe('RelayReader @catch', () => { // We still need to ensure that we will suspend if there is a request in flight. expect(isMissingData).toEqual(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.firstName', kind: 'missing_expected_data.log', @@ -465,7 +456,7 @@ describe('RelayReader @catch', () => { `; const owner = createOperationDescriptor(FooQuery, {}); - const {data, errorResponseFields, isMissingData} = read( + const {data, fieldErrors, isMissingData} = read( source, createReaderSelector(FooFragment, 'client:root', {}, owner.request), ); @@ -475,7 +466,7 @@ describe('RelayReader @catch', () => { // We still need to ensure that we will suspend if there is a request in flight. expect(isMissingData).toEqual(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.firstName', kind: 'missing_expected_data.log', @@ -509,17 +500,14 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {}); - const {data, errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {data, fieldErrors, isMissingData} = read(source, operation.fragment); expect(data).toEqual({me: {myAlias: null}}); // We still need to ensure that we will suspend if there is a request in flight. expect(isMissingData).toEqual(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.myAlias.firstName', kind: 'missing_expected_data.log', @@ -554,10 +542,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {}); - const {data, errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {data, fieldErrors, isMissingData} = read(source, operation.fragment); expect(data).toEqual({ me: {myAlias: {ok: false, errors: [{path: ['myAlias', 'firstName']}]}}, @@ -566,7 +551,7 @@ describe('RelayReader @catch', () => { // We still need to ensure that we will suspend if there is a request in flight. expect(isMissingData).toEqual(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.myAlias.firstName', kind: 'missing_expected_data.log', @@ -599,7 +584,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: { lastName: { @@ -609,7 +594,7 @@ describe('RelayReader @catch', () => { }, }); - expect(errorResponseFields).toBeNull(); + expect(fieldErrors).toBeNull(); }); it('if linked has catch to RESULT - but no error, response should reflect', () => { @@ -635,7 +620,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: { ok: true, @@ -645,7 +630,7 @@ describe('RelayReader @catch', () => { }, }); - expect(errorResponseFields).toBeNull(); + expect(fieldErrors).toBeNull(); }); it('if linked has catch to RESULT - with error, response should reflect', () => { @@ -679,7 +664,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: { ok: false, @@ -691,7 +676,7 @@ describe('RelayReader @catch', () => { }, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { error: {message: 'There was an error!', path: ['me', 'lastName']}, fieldPath: 'me.lastName', @@ -726,7 +711,7 @@ describe('RelayReader @catch', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: { errors: [ @@ -739,7 +724,7 @@ describe('RelayReader @catch', () => { }, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.lastName', handled: true, diff --git a/packages/relay-runtime/store/__tests__/RelayReader-ClientEdges-test.js b/packages/relay-runtime/store/__tests__/RelayReader-ClientEdges-test.js index c2fb5da5206f6..e993ab8f8e882 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-ClientEdges-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-ClientEdges-test.js @@ -25,6 +25,9 @@ const { const RelayStore = require('relay-runtime/store/RelayModernStore'); const {read} = require('relay-runtime/store/RelayReader'); const RelayRecordSource = require('relay-runtime/store/RelayRecordSource'); +const { + RELAY_READ_TIME_RESOLVER_KEY_PREFIX, +} = require('relay-runtime/store/RelayStoreUtils'); const { disallowConsoleErrors, disallowWarnings, @@ -154,7 +157,7 @@ describe('RelayReader Client Edges behavior', () => { expect(Array.from(seenRecords).sort()).toEqual([ '1', '1337', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, 'client:root', ]); expect(missingClientEdges?.length ?? 0).toEqual(0); @@ -189,7 +192,7 @@ describe('RelayReader Client Edges behavior', () => { expect(Array.from(seenRecords).sort()).toEqual([ '1', '1337', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, 'client:root', ]); expect(missingClientEdges?.length).toEqual(1); @@ -289,7 +292,7 @@ describe('RelayReader Client Edges behavior', () => { expect(Array.from(seenRecords).sort()).toEqual([ '1', '1337', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, 'client:root', ]); expect(missingClientEdges?.length ?? 0).toEqual(0); @@ -323,7 +326,7 @@ describe('RelayReader Client Edges behavior', () => { expect(me?.null_client_edge).toBe(null); expect(Array.from(seenRecords).sort()).toEqual([ '1', - 'client:1:null_client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}null_client_edge`, 'client:root', ]); expect(missingClientEdges?.length ?? 0).toEqual(0); @@ -366,7 +369,7 @@ describe('RelayReader Client Edges behavior', () => { '1', '1337', '1338', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, 'client:root', ]); expect(missingClientEdges?.length).toEqual(1); @@ -451,8 +454,8 @@ describe('RelayReader Client Edges behavior', () => { '1', '1337', '1338', - 'client:1337:another_client_edge', - 'client:1:client_edge', + `client:1337:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}another_client_edge`, + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, 'client:root', ]); expect(missingClientEdges?.length).toEqual(1); @@ -504,7 +507,7 @@ describe('RelayReader Client Edges behavior', () => { '1', '1337', '1338', - 'client:1338:client_edge', + `client:1338:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, 'client:root', ]); expect(missingClientEdges?.length).toEqual(1); diff --git a/packages/relay-runtime/store/__tests__/RelayReader-ExecResolvers-test.js b/packages/relay-runtime/store/__tests__/RelayReader-ExecResolvers-test.js index fee0843462c67..d7881e3d0e590 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-ExecResolvers-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-ExecResolvers-test.js @@ -36,7 +36,12 @@ export type TReaderTestUser = { name: ?string, }; -const modelMock = jest.fn(); +let modelMock; +let nameMock; +let bestFriendMock; +let friendsMock; +let user_oneMock; + /** * @RelayResolver RelayReaderExecResolversTestUser */ @@ -47,7 +52,6 @@ export function RelayReaderExecResolversTestUser(id: DataID): TReaderTestUser { }; } -const nameMock = jest.fn(); /** * @RelayResolver RelayReaderExecResolversTestUser.name: String */ @@ -56,7 +60,6 @@ export function name(user: TReaderTestUser): ?string { return user.name; } -const bestFriendMock = jest.fn(); /** * @RelayResolver RelayReaderExecResolversTestUser.best_friend: RelayReaderExecResolversTestUser */ @@ -67,7 +70,6 @@ export function best_friend( return {id: '2'}; } -const friendsMock = jest.fn(); /** * @RelayResolver RelayReaderExecResolversTestUser.friends: [RelayReaderExecResolversTestUser] */ @@ -78,7 +80,6 @@ export function friends( return [{id: '2'}, {id: '3'}, {id: '4'}]; } -const user_oneMock = jest.fn(); /** * @RelayResolver Query.RelayReaderExecResolversTest_user_one: RelayReaderExecResolversTestUser */ @@ -87,6 +88,14 @@ export function RelayReaderExecResolversTest_user_one(): IdOf<'RelayReaderExecRe return {id: '1'}; } +beforeEach(() => { + modelMock = jest.fn(); + nameMock = jest.fn(); + bestFriendMock = jest.fn(); + friendsMock = jest.fn(); + user_oneMock = jest.fn(); +}); + /** * Note that the reading of exec time resolvers is expected to be the same as * the reading of standard server queries. The main purpose of testing is to ensure @@ -94,9 +103,12 @@ export function RelayReaderExecResolversTest_user_one(): IdOf<'RelayReaderExecRe * not as read time resolver queries. */ describe('RelayReaderExecResolvers', () => { - it('reads exec_time_resolvers without calling the resolvers', () => { + it('reads exec_time_resolvers without calling the resolvers when provider returns true', () => { const Query = graphql` - query RelayReaderExecResolversTestRunsQuery @exec_time_resolvers { + query RelayReaderExecResolversTestQuery + @exec_time_resolvers( + enabledProvider: "relayReaderTestExecTimeResolversTrueProvider" + ) { RelayReaderExecResolversTest_user_one { name best_friend { @@ -151,4 +163,139 @@ describe('RelayReaderExecResolvers', () => { }, }); }); + + it('reads read time resolvers when exec time resolvers provider returns false', () => { + const Query = graphql` + query RelayReaderExecResolversTestFalseProviderQuery + @exec_time_resolvers( + enabledProvider: "relayReaderTestExecTimeResolversFalseProvider" + ) { + RelayReaderExecResolversTest_user_one { + name + best_friend { + name + } + friends { + name + } + } + } + `; + const operation = createOperationDescriptor(Query, {}); + const source = new RelayRecordSource({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + RelayReaderExecResolversTest_user_one: {__ref: '1'}, + }, + '1': { + __id: '1', + name: 'Alice', + friends: {__refs: ['2', '3', '4']}, + }, + '2': { + __id: '2', + name: 'Bob', + }, + '3': { + __id: '3', + name: 'Claire', + }, + '4': { + __id: '4', + name: 'Dennis', + }, + }); + const resolverStore = new RelayModernStore(source); + const {data} = read( + source, + operation.fragment, + new LiveResolverCache(() => source, resolverStore), + ); + + expect(modelMock).toBeCalled(); + expect(nameMock).toBeCalled(); + expect(user_oneMock).toBeCalled(); + expect(friendsMock).toBeCalled(); + expect(data).toEqual({ + RelayReaderExecResolversTest_user_one: { + best_friend: { + name: 'Bob', + }, + friends: [ + { + name: 'Bob', + }, + { + name: 'Claire', + }, + { + name: 'Dennis', + }, + ], + name: 'Alice', + }, + }); + }); + + it('reads exec time resolvers data correctly when client side directives are present, like @required', () => { + const Query = graphql` + query RelayReaderExecResolversTestClientDirectiveQuery + @exec_time_resolvers( + enabledProvider: "relayReaderTestExecTimeResolversTrueProvider" + ) { + RelayReaderExecResolversTest_user_one { + name @required(action: THROW) + best_friend { + name + } + friends { + name + } + } + } + `; + const operation = createOperationDescriptor(Query, {}); + const source = new RelayRecordSource({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + RelayReaderExecResolversTest_user_one: {__ref: '1'}, + }, + '1': { + __id: '1', + name: 'Alice', + friends: {__refs: ['2', '3', '4']}, + }, + '2': { + __id: '2', + name: 'Bob', + }, + '3': { + __id: '3', + name: 'Claire', + }, + '4': { + __id: '4', + name: 'Dennis', + }, + }); + const resolverStore = new RelayModernStore(source); + const {data} = read( + source, + operation.fragment, + new LiveResolverCache(() => source, resolverStore), + ); + + expect(modelMock).not.toBeCalled(); + expect(nameMock).not.toBeCalled(); + expect(user_oneMock).not.toBeCalled(); + expect(friendsMock).not.toBeCalled(); + expect(data).toEqual({ + RelayReaderExecResolversTest_user_one: { + name: 'Alice', + friends: [{name: 'Bob'}, {name: 'Claire'}, {name: 'Dennis'}], + }, + }); + }); }); diff --git a/packages/relay-runtime/store/__tests__/RelayReader-RelayErrorHandling-test.js b/packages/relay-runtime/store/__tests__/RelayReader-RelayErrorHandling-test.js index c6431d06b7827..49ce8682c544c 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-RelayErrorHandling-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-RelayErrorHandling-test.js @@ -11,6 +11,7 @@ 'use strict'; const {graphql} = require('../../query/GraphQLTag'); +const RelayFeatureFlags = require('../../util/RelayFeatureFlags'); const { createOperationDescriptor, } = require('../RelayModernOperationDescriptor'); @@ -19,7 +20,7 @@ const {read} = require('../RelayReader'); const RelayRecordSource = require('../RelayRecordSource'); describe('RelayReader error fields', () => { - it('adds the errors to errorResponseFields', () => { + it('adds the errors to fieldErrors', () => { const source = RelayRecordSource.create({ 'client:root': { __id: 'client:root', @@ -50,9 +51,9 @@ describe('RelayReader error fields', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({me: {lastName: null}}); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { owner: 'RelayReaderRelayErrorHandlingTest1Query', fieldPath: 'me.lastName', @@ -67,7 +68,7 @@ describe('RelayReader error fields', () => { ]); }); - it('adds the errors to errorResponseFields including missingData - without @catch', () => { + it('adds the errors to fieldErrors including missingData - without @catch', () => { const source = RelayRecordSource.create({ 'client:root': { __id: 'client:root', @@ -102,9 +103,9 @@ describe('RelayReader error fields', () => { } `; const operation = createOperationDescriptor(FooQuery, {size: 42}); - const {errorResponseFields} = read(source, operation.fragment); + const {fieldErrors} = read(source, operation.fragment); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { owner: 'RelayReaderRelayErrorHandlingTest4Query', fieldPath: 'me.lastName', @@ -125,7 +126,7 @@ describe('RelayReader error fields', () => { ]); }); - it('adds the errors to errorResponseFields including missingData within plural fields - without @catch', () => { + it('adds the errors to fieldErrors including missingData within plural fields - without @catch', () => { const source = RelayRecordSource.create({ 'client:root': { __id: 'client:root', @@ -160,9 +161,9 @@ describe('RelayReader error fields', () => { } `; const operation = createOperationDescriptor(FooQuery, {size: 42}); - const {errorResponseFields} = read(source, operation.fragment); + const {fieldErrors} = read(source, operation.fragment); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { owner: 'RelayReaderRelayErrorHandlingTestMissingPluralQuery', fieldPath: 'me.lastName', @@ -183,7 +184,7 @@ describe('RelayReader error fields', () => { ]); }); - it('adds the errors to errorResponseFields including missingData - with @catch', () => { + it('adds the errors to fieldErrors including missingData - with @catch', () => { const source = RelayRecordSource.create({ 'client:root': { __id: 'client:root', @@ -217,7 +218,7 @@ describe('RelayReader error fields', () => { } `; const operation = createOperationDescriptor(FooQuery, {size: 42}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); // we have a task out for adding path to missingData. Meantime that array is empty. expect(data).toEqual({ @@ -234,7 +235,7 @@ describe('RelayReader error fields', () => { }, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { error: {message: 'There was an error!', path: ['me', 'lastName']}, fieldPath: 'me.lastName', @@ -282,7 +283,7 @@ describe('RelayReader error fields', () => { `; const operation = createOperationDescriptor(FooQuery, {size: 42}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual({ me: { @@ -290,7 +291,7 @@ describe('RelayReader error fields', () => { }, }); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { error: {message: 'There was an error!', path: ['me', 'lastName']}, fieldPath: 'me.lastName', @@ -336,9 +337,9 @@ describe('RelayReader error fields', () => { `; const operation = createOperationDescriptor(FooQuery, {size: 42}); - const {errorResponseFields} = read(source, operation.fragment); + const {fieldErrors} = read(source, operation.fragment); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { error: {message: 'There was an error!', path: ['me', 'lastName']}, fieldPath: 'me.lastName', @@ -385,9 +386,9 @@ describe('RelayReader error fields', () => { `; const operation = createOperationDescriptor(FooQuery, {size: 42}); - const {errorResponseFields} = read(source, operation.fragment); + const {fieldErrors} = read(source, operation.fragment); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.client_edge.firstName', kind: 'missing_expected_data.throw', @@ -427,20 +428,21 @@ describe('RelayReader error fields', () => { @throwOnFieldError { me { astrological_sign { - notes # Not in the store! + # Compiler forces us to use @catch here + notes @catch(to: NULL) # Not in the store! } } } `; const operation = createOperationDescriptor(FooQuery, {}); - const {errorResponseFields} = store.lookup(operation.fragment); + const {fieldErrors} = store.lookup(operation.fragment); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.astrological_sign.notes', kind: 'missing_expected_data.throw', - handled: false, + handled: true, owner: 'RelayReaderRelayErrorHandlingTestResolverClientEdgeClientObjectWithMissingDataQuery', }, @@ -465,17 +467,18 @@ describe('RelayReader error fields', () => { query RelayReaderRelayErrorHandlingTestResolverClientPluralEdgeClientObjectWithMissingDataQuery @throwOnFieldError { all_astrological_signs { - notes # Not in the store! + # Compiler forces us to use @catch here + notes @catch(to: NULL) # Not in the store! } } `; const operation = createOperationDescriptor(FooQuery, {}); - const {errorResponseFields} = store.lookup(operation.fragment); - for (let i = 0; i < errorResponseFields.length; i++) { - expect(errorResponseFields[i]).toEqual({ + const {fieldErrors} = store.lookup(operation.fragment); + for (let i = 0; i < fieldErrors.length; i++) { + expect(fieldErrors[i]).toEqual({ fieldPath: `all_astrological_signs.${i}.notes`, kind: 'missing_expected_data.throw', - handled: false, + handled: true, owner: 'RelayReaderRelayErrorHandlingTestResolverClientPluralEdgeClientObjectWithMissingDataQuery', }); @@ -512,13 +515,10 @@ describe('RelayReader error fields', () => { } `; const operation = createOperationDescriptor(FooQuery, {}); - const {errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {fieldErrors, isMissingData} = read(source, operation.fragment); expect(isMissingData).toBe(false); - expect(errorResponseFields).toEqual(null); + expect(fieldErrors).toEqual(null); }); it('does report missing data within an inline fragment that does match', () => { @@ -552,13 +552,10 @@ describe('RelayReader error fields', () => { } `; const operation = createOperationDescriptor(FooQuery, {}); - const {errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {fieldErrors, isMissingData} = read(source, operation.fragment); expect(isMissingData).toBe(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ // We are missing the metadata bout the interface { fieldPath: 'node.', @@ -608,13 +605,10 @@ describe('RelayReader error fields', () => { } `; const operation = createOperationDescriptor(FooQuery, {}); - const {errorResponseFields, isMissingData} = read( - source, - operation.fragment, - ); + const {fieldErrors, isMissingData} = read(source, operation.fragment); expect(isMissingData).toBe(true); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'also_me.name', handled: false, @@ -635,4 +629,251 @@ describe('RelayReader error fields', () => { }, ]); }); + + let wasNoncompliantErrorHandlingOnListsEnabled; + + beforeEach(() => { + wasNoncompliantErrorHandlingOnListsEnabled = + RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS; + }); + + afterEach(() => { + RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS = + wasNoncompliantErrorHandlingOnListsEnabled; + }); + + describe('when noncompliant error handling on lists is enabled', () => { + beforeEach(() => { + RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS = true; + }); + + describe('when query has @throwOnFieldError directive', () => { + it('has errors that will throw when the linked field is an empty list', () => { + const source = RelayRecordSource.create({ + '1': { + __id: '1', + __typename: 'User', + 'friends(first:3)': { + __ref: 'client:1:friends(first:3)', + }, + id: '1', + }, + 'client:1:friends(first:3)': { + __id: 'client:1:friends(first:3)', + __typename: 'FriendsConnection', + __errors: { + edges: [ + { + message: 'There was an error!', + }, + ], + }, + edges: { + __refs: [], + }, + }, + 'client:root': { + __id: 'client:root', + __typename: '__Root', + 'node(id:"1")': {__ref: '1'}, + }, + }); + + const FooQuery = graphql` + query RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery + @throwOnFieldError { + node(id: "1") { + id + __typename + ... on User { + friends(first: 3) { + edges { + cursor + } + } + } + } + } + `; + const operation = createOperationDescriptor(FooQuery, {}); + const {fieldErrors} = read(source, operation.fragment); + + expect(fieldErrors).toEqual([ + { + fieldPath: '', + handled: false, + error: {message: 'There was an error!'}, + kind: 'relay_field_payload.error', + owner: + 'RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery', + shouldThrow: true, + }, + ]); + }); + + it('has errors that will throw when the scalar field is an empty list', () => { + const source = RelayRecordSource.create({ + '1': { + __id: '1', + __typename: 'User', + __errors: { + emailAddresses: [ + { + message: 'There was an error!', + }, + ], + }, + id: '1', + emailAddresses: [], + }, + 'client:root': { + __id: 'client:root', + __typename: '__Root', + 'node(id:"1")': {__ref: '1'}, + }, + }); + + const FooQuery = graphql` + query RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery + @throwOnFieldError { + node(id: "1") { + id + __typename + ... on User { + emailAddresses + } + } + } + `; + const operation = createOperationDescriptor(FooQuery, {}); + const {fieldErrors} = read(source, operation.fragment); + + expect(fieldErrors).toEqual([ + { + fieldPath: '', + handled: false, + error: {message: 'There was an error!'}, + kind: 'relay_field_payload.error', + owner: + 'RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery', + shouldThrow: true, + }, + ]); + }); + }); + + describe('when query does not have the @throwOnFieldError directive', () => { + it('has errors that wont throw when the linked field is an empty list', () => { + const source = RelayRecordSource.create({ + '1': { + __id: '1', + __typename: 'User', + 'friends(first:3)': { + __ref: 'client:1:friends(first:3)', + }, + id: '1', + }, + 'client:1:friends(first:3)': { + __id: 'client:1:friends(first:3)', + __typename: 'FriendsConnection', + __errors: { + edges: [ + { + message: 'There was an error!', + }, + ], + }, + edges: { + __refs: [], + }, + }, + 'client:root': { + __id: 'client:root', + __typename: '__Root', + 'node(id:"1")': {__ref: '1'}, + }, + }); + + const FooQuery = graphql` + query RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery { + node(id: "1") { + id + __typename + ... on User { + friends(first: 3) { + edges { + cursor + } + } + } + } + } + `; + const operation = createOperationDescriptor(FooQuery, {}); + const {data, fieldErrors} = read(source, operation.fragment); + + expect(data.node.friends.edges).toEqual([]); + expect(fieldErrors).toEqual([ + { + fieldPath: '', + handled: false, + error: {message: 'There was an error!'}, + kind: 'relay_field_payload.error', + owner: + 'RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery', + shouldThrow: false, + }, + ]); + }); + + it('has errors that wont throw when the scalar field is an empty list', () => { + const source = RelayRecordSource.create({ + '1': { + __id: '1', + __typename: 'User', + __errors: { + emailAddresses: [ + { + message: 'There was an error!', + }, + ], + }, + id: '1', + emailAddresses: [], + }, + 'client:root': { + __id: 'client:root', + __typename: '__Root', + 'node(id:"1")': {__ref: '1'}, + }, + }); + + const FooQuery = graphql` + query RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery { + node(id: "1") { + id + __typename + ... on User { + emailAddresses + } + } + } + `; + const operation = createOperationDescriptor(FooQuery, {}); + const {data, fieldErrors} = read(source, operation.fragment); + expect(data.node.emailAddresses).toEqual([]); + expect(fieldErrors).toEqual([ + { + fieldPath: '', + handled: false, + error: {message: 'There was an error!'}, + kind: 'relay_field_payload.error', + owner: + 'RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery', + shouldThrow: false, + }, + ]); + }); + }); + }); }); diff --git a/packages/relay-runtime/store/__tests__/RelayReader-RequiredFields-test.js b/packages/relay-runtime/store/__tests__/RelayReader-RequiredFields-test.js index 2cec55e88c78b..afce9652b2877 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-RequiredFields-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-RequiredFields-test.js @@ -21,6 +21,9 @@ const { LiveResolverCache, } = require('relay-runtime/store/live-resolvers/LiveResolverCache'); const RelayModernStore = require('relay-runtime/store/RelayModernStore'); +const { + RELAY_READ_TIME_RESOLVER_KEY_PREFIX, +} = require('relay-runtime/store/RelayStoreUtils'); describe('RelayReader @required', () => { it('bubbles @required(action: LOG) scalars up to LinkedField', () => { @@ -143,9 +146,9 @@ describe('RelayReader @required', () => { } `; const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read(source, operation.fragment); + const {data, fieldErrors} = read(source, operation.fragment); expect(data).toEqual(null); - expect(errorResponseFields[0].fieldPath).toBe('me.lastName'); + expect(fieldErrors[0].fieldPath).toBe('me.lastName'); }); it('bubbles @required(action: LOG) scalars up to LinkedField even if subsequent fields are not unexpectedly null', () => { @@ -893,7 +896,7 @@ describe('RelayReader @required', () => { const store = new RelayModernStore(source); const operation = createOperationDescriptor(FooQuery, {}); const resolverCache = new LiveResolverCache(() => source, store); - const {data, errorResponseFields} = read( + const {data, fieldErrors} = read( source, operation.fragment, resolverCache, @@ -910,7 +913,7 @@ describe('RelayReader @required', () => { }, }); // these are "handled" because the field with the required error was caught - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { fieldPath: 'me.client_object', handled: true, @@ -946,12 +949,8 @@ describe('RelayReader @required', () => { const store = new RelayModernStore(source); const operation = createOperationDescriptor(FooQuery, {}); const resolverCache = new LiveResolverCache(() => source, store); - const {errorResponseFields} = read( - source, - operation.fragment, - resolverCache, - ); - expect(errorResponseFields).toEqual([ + const {fieldErrors} = read(source, operation.fragment, resolverCache); + expect(fieldErrors).toEqual([ { fieldPath: 'me.client_object', kind: 'missing_required_field.throw', @@ -992,13 +991,13 @@ describe('RelayReader @required', () => { const store = new RelayModernStore(source); const operation = createOperationDescriptor(FooQuery, {}); const resolverCache = new LiveResolverCache(() => source, store); - const {data, errorResponseFields} = read( + const {data, fieldErrors} = read( source, operation.fragment, resolverCache, ); expect(data).toEqual({me: {astrological_sign: {name: 'Pisces'}}}); - expect(errorResponseFields).toBe(null); + expect(fieldErrors).toBe(null); }); test('does not throw when required plural field is present', () => { @@ -1025,13 +1024,13 @@ describe('RelayReader @required', () => { const store = new RelayModernStore(source); const operation = createOperationDescriptor(FooQuery, {}); const resolverCache = new LiveResolverCache(() => source, store); - const {data, errorResponseFields} = read( + const {data, fieldErrors} = read( source, operation.fragment, resolverCache, ); expect(data.all_astrological_signs.length).toBe(12); - expect(errorResponseFields).toBe(null); + expect(fieldErrors).toBe(null); }); test('does not throw when @live required field is suspended', () => { @@ -1054,9 +1053,9 @@ describe('RelayReader @required', () => { const operation = createOperationDescriptor(FooQuery, {}); const resolverCache = new LiveResolverCache(() => source, store); const snapshot = read(source, operation.fragment, resolverCache); - expect(snapshot.errorResponseFields).toEqual(null); + expect(snapshot.fieldErrors).toEqual(null); expect(snapshot.missingLiveResolverFields).toEqual([ - 'client:root:live_user_resolver_always_suspend', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}live_user_resolver_always_suspend`, ]); }); }); diff --git a/packages/relay-runtime/store/__tests__/RelayReader-Resolver-test.js b/packages/relay-runtime/store/__tests__/RelayReader-Resolver-test.js index 89e69dbeb4b87..d96dc698c3cc9 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-Resolver-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-Resolver-test.js @@ -10,6 +10,7 @@ */ 'use strict'; + import type {Snapshot} from '../RelayStoreTypes'; const { @@ -35,6 +36,7 @@ const RelayStore = require('relay-runtime/store/RelayModernStore'); const {read} = require('relay-runtime/store/RelayReader'); const RelayRecordSource = require('relay-runtime/store/RelayRecordSource'); const { + RELAY_READ_TIME_RESOLVER_KEY_PREFIX, RELAY_RESOLVER_INVALIDATION_KEY, } = require('relay-runtime/store/RelayStoreUtils'); const { @@ -86,7 +88,7 @@ it('returns the result of the resolver function', () => { expect(Array.from(seenRecords).sort()).toEqual([ '1', - 'client:1:greeting', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}greeting`, 'client:root', ]); }); @@ -183,8 +185,8 @@ describe('Relay resolver - Field Error Handling', () => { const operation = createOperationDescriptor(FooQuery, {}); const store = new RelayStore(source, {gcReleaseBufferSize: 0}); - const {errorResponseFields} = store.lookup(operation.fragment); - expect(errorResponseFields).toEqual([ + const {fieldErrors} = store.lookup(operation.fragment); + expect(fieldErrors).toEqual([ { fieldPath: 'me.lastName', kind: 'relay_field_payload.error', @@ -221,8 +223,8 @@ it('propagates @required errors from the resolver up to the reader', () => { const operation = createOperationDescriptor(FooQuery, {}); const store = new RelayStore(source, {gcReleaseBufferSize: 0}); - const {errorResponseFields} = store.lookup(operation.fragment); - expect(errorResponseFields).toEqual([ + const {fieldErrors} = store.lookup(operation.fragment); + expect(fieldErrors).toEqual([ { kind: 'missing_required_field.log', owner: 'UserRequiredNameResolver', @@ -240,7 +242,7 @@ it('propagates @required errors from the resolver up to the reader', () => { // Lookup a second time to ensure that we still report the missing fields when // reading from the cache. - const {errorResponseFields: missingRequiredFieldsTakeTwo} = store.lookup( + const {fieldErrors: missingRequiredFieldsTakeTwo} = store.lookup( operation.fragment, ); @@ -320,8 +322,8 @@ it('merges @required logs from resolver field with parent', () => { const operation = createOperationDescriptor(FooQuery, {}); const store = new RelayStore(source, {gcReleaseBufferSize: 0}); - const {errorResponseFields} = store.lookup(operation.fragment); - expect(errorResponseFields).toEqual([ + const {fieldErrors} = store.lookup(operation.fragment); + expect(fieldErrors).toEqual([ { kind: 'missing_required_field.log', owner: 'UserRequiredNameResolver', @@ -344,7 +346,7 @@ it('merges @required logs from resolver field with parent', () => { // Lookup a second time to ensure that we still report the missing fields when // reading from the cache. - const {errorResponseFields: missingRequiredFieldsTakeTwo} = store.lookup( + const {fieldErrors: missingRequiredFieldsTakeTwo} = store.lookup( operation.fragment, ); @@ -396,10 +398,10 @@ it('propagates @required(action: THROW) errors from the resolver up to the reade const store = new RelayStore(source, {gcReleaseBufferSize: 0}); const beforeCallCount = requiredThrowNameCalls.count; - const {errorResponseFields, data} = store.lookup(operation.fragment); + const {fieldErrors, data} = store.lookup(operation.fragment); expect(data).toEqual({me: {required_throw_name: null}}); expect(requiredThrowNameCalls.count).toBe(beforeCallCount); - expect(errorResponseFields).toEqual([ + expect(fieldErrors).toEqual([ { kind: 'missing_required_field.throw', owner: 'UserRequiredThrowNameResolver', @@ -410,7 +412,7 @@ it('propagates @required(action: THROW) errors from the resolver up to the reade // Lookup a second time to ensure that we still report the missing fields when // reading from the cache. - const {errorResponseFields: missingRequiredFieldsTakeTwo, data: dataTakeTwo} = + const {fieldErrors: missingRequiredFieldsTakeTwo, data: dataTakeTwo} = store.lookup(operation.fragment); expect(dataTakeTwo).toEqual({me: {required_throw_name: null}}); @@ -618,7 +620,7 @@ it.each([true, false])( const resolverCacheRecord = environment .getStore() .getSource() - .get('client:1:constant_dependent'); + .get(`client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}constant_dependent`); invariant(resolverCacheRecord != null, 'Expected a resolver cache record'); const isMaybeInvalid = RelayModernRecord.getValue( @@ -1038,14 +1040,10 @@ it('Returns null and includes errors when the resolver throws', () => { const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read( - source, - operation.fragment, - resolverCache, - ); + const {data, fieldErrors} = read(source, operation.fragment, resolverCache); expect(data).toEqual({me: {always_throws: null}}); // Resolver result - expect(errorResponseFields).toMatchInlineSnapshot(` + expect(fieldErrors).toMatchInlineSnapshot(` Array [ Object { "error": [Error: I always throw. What did you expect?], @@ -1059,7 +1057,7 @@ it('Returns null and includes errors when the resolver throws', () => { `); // Subsequent read should also read the same error/path - const {data: data2, errorResponseFields: relayResolverErrors2} = read( + const {data: data2, fieldErrors: relayResolverErrors2} = read( source, operation.fragment, resolverCache, @@ -1106,14 +1104,10 @@ it('Returns null and includes errors when a transitive resolver throws', () => { const operation = createOperationDescriptor(FooQuery, {id: '1'}); - const {data, errorResponseFields} = read( - source, - operation.fragment, - resolverCache, - ); + const {data, fieldErrors} = read(source, operation.fragment, resolverCache); expect(data).toEqual({me: {always_throws_transitively: null}}); // Resolver result - expect(errorResponseFields).toMatchInlineSnapshot(` + expect(fieldErrors).toMatchInlineSnapshot(` Array [ Object { "error": [Error: I always throw. What did you expect?], @@ -1127,7 +1121,7 @@ it('Returns null and includes errors when a transitive resolver throws', () => { `); // Subsequent read should also read the same error/path - const {data: data2, errorResponseFields: relayResolverErrors2} = read( + const {data: data2, fieldErrors: relayResolverErrors2} = read( source, operation.fragment, resolverCache, @@ -1168,14 +1162,10 @@ it('Catches errors thrown before calling readFragment', () => { const operation = createOperationDescriptor(FooQuery, {}); - const {data, errorResponseFields} = read( - source, - operation.fragment, - resolverCache, - ); + const {data, fieldErrors} = read(source, operation.fragment, resolverCache); expect(data).toEqual({throw_before_read: null}); // Resolver result - expect(errorResponseFields).toMatchInlineSnapshot(` + expect(fieldErrors).toMatchInlineSnapshot(` Array [ Object { "error": [Error: Purposefully throwing before reading to exercise an edge case.], diff --git a/packages/relay-runtime/store/__tests__/RelayReader-test.js b/packages/relay-runtime/store/__tests__/RelayReader-test.js index 46dbe8bb2d16c..ae269c292e8fc 100644 --- a/packages/relay-runtime/store/__tests__/RelayReader-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReader-test.js @@ -1481,6 +1481,7 @@ describe('RelayReader', () => { viewer { actor { ...RelayReaderTestShouldNotConsiderDataMissingIfTheFragmentTypeDoesNotMatchTheDataUserProfile + @dangerously_unaliased_fixme } } } @@ -1620,6 +1621,7 @@ describe('RelayReader', () => { query RelayReaderTestStreamConnectionUserQuery($id: ID!) { node(id: $id) { ...RelayReaderTestStreamConnectionUserProfile + @dangerously_unaliased_fixme } } `; @@ -1828,7 +1830,7 @@ describe('RelayReader', () => { query RelayReaderTestActorChangeQuery { viewer { actor @fb_actor_change { - ...RelayReaderTestActorChangeFragment + ...RelayReaderTestActorChangeFragment @dangerously_unaliased_fixme } } } diff --git a/packages/relay-runtime/store/__tests__/RelayReferenceMarker-test.js b/packages/relay-runtime/store/__tests__/RelayReferenceMarker-test.js index 24c01f82c19a2..ba4088e759e83 100644 --- a/packages/relay-runtime/store/__tests__/RelayReferenceMarker-test.js +++ b/packages/relay-runtime/store/__tests__/RelayReferenceMarker-test.js @@ -21,7 +21,7 @@ import {createNormalizationSelector} from '../RelayModernSelector'; import RelayModernStore from '../RelayModernStore'; import RelayRecordSource from '../RelayRecordSource'; import {mark} from '../RelayReferenceMarker'; -import {ROOT_ID} from '../RelayStoreUtils'; +import {RELAY_READ_TIME_RESOLVER_KEY_PREFIX, ROOT_ID} from '../RelayStoreUtils'; describe('RelayReferenceMarker', () => { let source; @@ -93,7 +93,9 @@ describe('RelayReferenceMarker', () => { name } } - ...RelayReferenceMarkerTest1Fragment @arguments(size: $size) + ...RelayReferenceMarkerTest1Fragment + @dangerously_unaliased_fixme + @arguments(size: $size) } } `; @@ -405,7 +407,7 @@ describe('RelayReferenceMarker', () => { node(id: $id) { id __typename - ...RelayReferenceMarkerTest2Fragment + ...RelayReferenceMarkerTest2Fragment @dangerously_unaliased_fixme } } `; @@ -493,7 +495,7 @@ describe('RelayReferenceMarker', () => { BarQuery = graphql` query RelayReferenceMarkerTest5Query($id: ID!) { node(id: $id) { - ...RelayReferenceMarkerTest3Fragment + ...RelayReferenceMarkerTest3Fragment @dangerously_unaliased_fixme } } `; @@ -841,11 +843,14 @@ describe('RelayReferenceMarker', () => { 'client:root': { __id: 'client:root', __typename: '__Root', - counter_no_fragment: { - __ref: 'client:root:counter_no_fragment', + // $FlowFixMe[invalid-computed-prop] + [`${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_no_fragment`]: { + __ref: `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_no_fragment`, }, }, - 'client:root:counter_no_fragment': {}, + // $FlowFixMe[invalid-computed-prop] + [`client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_no_fragment`]: + {}, }; const nodes = { FooQuery: graphql` @@ -879,7 +884,7 @@ describe('RelayReferenceMarker', () => { ); expect(Array.from(references).sort()).toEqual([ 'client:root', - 'client:root:counter_no_fragment', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_no_fragment`, ]); }); it('with fragment dependency is retained', () => { @@ -888,15 +893,17 @@ describe('RelayReferenceMarker', () => { __id: 'client:root', __typename: 'Query', me: {__ref: '1'}, - counter: { - __ref: 'client:root:counter', + // $FlowFixMe[invalid-computed-prop] + [`${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`]: { + __ref: `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, }, }, '1': { __id: '1', __typename: 'User', }, - 'client:root:counter': {}, + // $FlowFixMe[invalid-computed-prop] + [`client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`]: {}, }; const nodes = { FooQuery: graphql` @@ -931,7 +938,7 @@ describe('RelayReferenceMarker', () => { expect(Array.from(references).sort()).toEqual([ '1', 'client:root', - 'client:root:counter', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, ]); }); it('with @edgeTo client object is retained', () => { @@ -1005,7 +1012,7 @@ describe('RelayReferenceMarker', () => { 'client:AstrologicalSign:Taurus', 'client:AstrologicalSign:Virgo', 'client:root', - 'client:root:all_astrological_signs', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}all_astrological_signs`, ]); }); }); @@ -1048,7 +1055,7 @@ describe('RelayReferenceMarker', () => { BarQuery = graphql` query RelayReferenceMarkerTest6Query($id: ID!) { node(id: $id) { - ...RelayReferenceMarkerTest4Fragment + ...RelayReferenceMarkerTest4Fragment @dangerously_unaliased_fixme } } `; @@ -1402,7 +1409,9 @@ describe('RelayReferenceMarker', () => { Query = graphql` query RelayReferenceMarkerTest7Query($id: ID!) { node(id: $id) { - ...RelayReferenceMarkerTest5Fragment @defer(label: "TestFragment") + ...RelayReferenceMarkerTest5Fragment + @dangerously_unaliased_fixme + @defer(label: "TestFragment") } } `; @@ -1478,7 +1487,7 @@ describe('RelayReferenceMarker', () => { Query = graphql` query RelayReferenceMarkerTest8Query($id: ID!) { node(id: $id) { - ...RelayReferenceMarkerTest6Fragment + ...RelayReferenceMarkerTest6Fragment @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/store/__tests__/RelayResponseNormalizer-test.js b/packages/relay-runtime/store/__tests__/RelayResponseNormalizer-test.js index c658a1d48a2bb..89ead58599777 100644 --- a/packages/relay-runtime/store/__tests__/RelayResponseNormalizer-test.js +++ b/packages/relay-runtime/store/__tests__/RelayResponseNormalizer-test.js @@ -37,6 +37,7 @@ describe('RelayResponseNormalizer', () => { const defaultOptions = { getDataID: defaultGetDataID, treatMissingFieldsAsNull: false, + log: null, }; it('normalizes queries', () => { @@ -135,12 +136,14 @@ describe('RelayResponseNormalizer', () => { __refs: [edgeID1, null, edgeID2], }, }, + // $FlowFixMe[invalid-computed-prop] [edgeID1]: { __id: edgeID1, __typename: 'FriendsEdge', cursor: 'cursor:2', node: {__ref: '2'}, }, + // $FlowFixMe[invalid-computed-prop] [edgeID2]: { __id: edgeID2, __typename: 'FriendsEdge', @@ -397,7 +400,7 @@ describe('RelayResponseNormalizer', () => { BarQuery = graphql` query RelayResponseNormalizerTest4Query($id: ID!) { node(id: $id) { - ...RelayResponseNormalizerTestFragment + ...RelayResponseNormalizerTestFragment @dangerously_unaliased_fixme } } `; @@ -674,7 +677,7 @@ describe('RelayResponseNormalizer', () => { BarQuery = graphql` query RelayResponseNormalizerTest5Query($id: ID!) { node(id: $id) { - ...RelayResponseNormalizerTest1Fragment + ...RelayResponseNormalizerTest1Fragment @dangerously_unaliased_fixme } } `; @@ -897,6 +900,7 @@ describe('RelayResponseNormalizer', () => { ) { node(id: $id) { ...RelayResponseNormalizerTest2Fragment + @dangerously_unaliased_fixme @defer(label: "TestFragment", if: $enableDefer) } } @@ -947,6 +951,7 @@ describe('RelayResponseNormalizer', () => { query RelayResponseNormalizerTest7Query($id: ID!) { node(id: $id) { ...RelayResponseNormalizerTest3Fragment + @dangerously_unaliased_fixme @defer(label: "TestFragment", if: true) } } @@ -1012,6 +1017,7 @@ describe('RelayResponseNormalizer', () => { ) { node(id: $id) { ...RelayResponseNormalizerTest4Fragment + @dangerously_unaliased_fixme @defer(label: "TestFragment", if: $enableDefer) } } @@ -1077,6 +1083,7 @@ describe('RelayResponseNormalizer', () => { ... on Feedback { actors { ...RelayResponseNormalizerTest5Fragment + @dangerously_unaliased_fixme @defer(label: "TestFragment", if: true) } } @@ -1169,6 +1176,7 @@ describe('RelayResponseNormalizer', () => { query RelayResponseNormalizerTest10Query($id: ID!) { node(id: $id) { ...RelayResponseNormalizerTest6Fragment + @dangerously_unaliased_fixme @defer(label: "TestFragment") } } @@ -1225,7 +1233,7 @@ describe('RelayResponseNormalizer', () => { $enableStream: Boolean! ) { node(id: $id) { - ...RelayResponseNormalizerTest7Fragment + ...RelayResponseNormalizerTest7Fragment @dangerously_unaliased_fixme } } `; @@ -1282,7 +1290,7 @@ describe('RelayResponseNormalizer', () => { const Query = graphql` query RelayResponseNormalizerTestQuery($id: ID!) { node(id: $id) { - ...RelayResponseNormalizerTest8Fragment + ...RelayResponseNormalizerTest8Fragment @dangerously_unaliased_fixme } } `; @@ -1351,7 +1359,7 @@ describe('RelayResponseNormalizer', () => { $enableStream: Boolean! ) { node(id: $id) { - ...RelayResponseNormalizerTest9Fragment + ...RelayResponseNormalizerTest9Fragment @dangerously_unaliased_fixme } } `; @@ -1424,6 +1432,7 @@ describe('RelayResponseNormalizer', () => { query RelayResponseNormalizerTest13Query($id: ID!) { node(id: $id) { ...RelayResponseNormalizerTest10Fragment + @dangerously_unaliased_fixme } } `; @@ -1508,6 +1517,7 @@ describe('RelayResponseNormalizer', () => { query RelayResponseNormalizerTest14Query($id: ID!) { node(id: $id) { ...RelayResponseNormalizerTest11Fragment + @dangerously_unaliased_fixme } } `; @@ -1941,7 +1951,7 @@ describe('RelayResponseNormalizer', () => { id: '1', }), fooPayload, - {getDataID, treatMissingFieldsAsNull: false}, + {getDataID, treatMissingFieldsAsNull: false, log: null}, ); expect(recordSource.toJSON()).toEqual({ 'client:root': { @@ -2014,7 +2024,7 @@ describe('RelayResponseNormalizer', () => { id: '1', }), fooPayload0, - {getDataID, treatMissingFieldsAsNull: false}, + {getDataID, treatMissingFieldsAsNull: false, log: null}, ); normalize( recordSource, @@ -2022,7 +2032,7 @@ describe('RelayResponseNormalizer', () => { id: '1', }), fooPayload1, - {getDataID, treatMissingFieldsAsNull: false}, + {getDataID, treatMissingFieldsAsNull: false, log: null}, ); expect(recordSource.toJSON()).toEqual({ 'client:root': { @@ -2062,7 +2072,7 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload, - {getDataID, treatMissingFieldsAsNull: false}, + {getDataID, treatMissingFieldsAsNull: false, log: null}, ); expect(recordSource.toJSON()).toEqual({ '1:Page': { @@ -2131,7 +2141,11 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload, - {getDataID: getNullAsDataID, treatMissingFieldsAsNull: false}, + { + getDataID: getNullAsDataID, + treatMissingFieldsAsNull: false, + log: null, + }, ); expect(recordSource.toJSON()).toEqual(expectedData); expect(getNullAsDataID).toBeCalledTimes(3); @@ -2144,7 +2158,11 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload, - {getDataID: getNullAsDataID, treatMissingFieldsAsNull: false}, + { + getDataID: getNullAsDataID, + treatMissingFieldsAsNull: false, + log: null, + }, ); expect(recordSource.toJSON()).toEqual({ 'client:root': { @@ -2220,7 +2238,7 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload, - {getDataID, treatMissingFieldsAsNull: false}, + {getDataID, treatMissingFieldsAsNull: false, log: null}, ); expect(recordSource.toJSON()).toEqual({ '1:Page': { @@ -2291,7 +2309,11 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload, - {getDataID: getNullAsDataID, treatMissingFieldsAsNull: false}, + { + getDataID: getNullAsDataID, + treatMissingFieldsAsNull: false, + log: null, + }, ); expect(recordSource.toJSON()).toEqual(expectedData); expect(getNullAsDataID).toBeCalledTimes(3); @@ -2327,7 +2349,11 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload, - {getDataID: getNullAsDataID, treatMissingFieldsAsNull: false}, + { + getDataID: getNullAsDataID, + treatMissingFieldsAsNull: false, + log: null, + }, ); const result = recordSource.toJSON(); expect(result['test:root:node(id:"1")']).toEqual({ @@ -2356,7 +2382,11 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload, - {getDataID: getNullAsDataID, treatMissingFieldsAsNull: false}, + { + getDataID: getNullAsDataID, + treatMissingFieldsAsNull: false, + log: null, + }, ); expect(recordSource.toJSON()).toEqual({ 'client:root': { @@ -2443,7 +2473,7 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload0, - {getDataID, treatMissingFieldsAsNull: false}, + {getDataID, treatMissingFieldsAsNull: false, log: null}, ); normalize( recordSource, @@ -2451,7 +2481,7 @@ describe('RelayResponseNormalizer', () => { id: '1', }), payload1, - {getDataID, treatMissingFieldsAsNull: false}, + {getDataID, treatMissingFieldsAsNull: false, log: null}, ); expect(recordSource.toJSON()).toEqual({ '1:Page': { @@ -2518,7 +2548,7 @@ describe('RelayResponseNormalizer', () => { query RelayResponseNormalizerTest_pvQuery($id: ID!) { node(id: $id) { id - ...RelayResponseNormalizerTest_pvFragment + ...RelayResponseNormalizerTest_pvFragment @dangerously_unaliased_fixme } } `; @@ -3670,6 +3700,7 @@ describe('RelayResponseNormalizer', () => { viewer { actor @fb_actor_change { ...RelayResponseNormalizerTestActorChangeFragment + @dangerously_unaliased_fixme } } } @@ -3999,6 +4030,7 @@ describe('RelayResponseNormalizer', () => { } actor @fb_actor_change { ...RelayResponseNormalizerTestActorChangeFragment + @dangerously_unaliased_fixme } } } @@ -4285,18 +4317,21 @@ describe('RelayResponseNormalizer', () => { __refs: [edge0ID, edge1ID, edge2ID], }, }, + // $FlowFixMe[invalid-computed-prop] [edge0ID]: { __id: edge0ID, __typename: 'FriendsEdge', cursor: 'cursor:2', node: {__ref: '2'}, }, + // $FlowFixMe[invalid-computed-prop] [edge1ID]: { __id: edge1ID, __typename: 'FriendsEdge', cursor: 'cursor:3', node: {__ref: '3'}, }, + // $FlowFixMe[invalid-computed-prop] [edge2ID]: { __id: edge2ID, __typename: 'FriendsEdge', @@ -4491,7 +4526,7 @@ describe('RelayResponseNormalizer', () => { RelayFeatureFlags.ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS = true; }); - it('stores field errors on an empty list', () => { + it('stores field errors on an linked field that is an empty list', () => { const FooQuery = graphql` query RelayResponseNormalizerTest40Query($id: ID!) { node(id: $id) { @@ -4553,7 +4588,68 @@ describe('RelayResponseNormalizer', () => { }, ], }, - edges: null, + edges: { + __refs: [], + }, + }, + 'client:root': { + __id: 'client:root', + __typename: '__Root', + 'node(id:"1")': {__ref: '1'}, + }, + }); + }); + + it('stores field errors on an scalar field that is an empty list', () => { + const FooQuery = graphql` + query RelayResponseNormalizerTest41Query($id: ID!) { + node(id: $id) { + id + __typename + ... on User { + emailAddresses + } + } + } + `; + const payload = { + node: { + id: '1', + __typename: 'User', + emailAddresses: [], + }, + }; + const errors = [ + { + message: 'There was an error!', + path: ['node', 'emailAddresses'], + }, + ]; + const recordSource = new RelayRecordSource(); + recordSource.set(ROOT_ID, RelayModernRecord.create(ROOT_ID, ROOT_TYPE)); + normalize( + recordSource, + createNormalizationSelector(FooQuery.operation, ROOT_ID, { + id: '1', + size: 32, + }), + payload, + defaultOptions, + errors, + ); + expect(recordSource.toJSON()).toEqual({ + '1': { + __id: '1', + __typename: 'User', + __errors: { + emailAddresses: [ + { + message: 'There was an error!', + }, + ], + }, + id: '1', + emailAddresses: [], }, 'client:root': { __id: 'client:root', diff --git a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest4Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest4Query.graphql.js index 5402279a15563..21f997df23695 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest4Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest4Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<63df037fd0f87eebae863494a08cb57f>> * @flow * @lightSyntaxTransform * @nogrep @@ -176,7 +176,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a9b9699255a75903b81e31abf46a581d"; + (node/*: any*/).hash = "15016c70d2233156a2b3cfba19ebded8"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest5Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest5Query.graphql.js index dbe1d2a45032d..551f2b5d3c5b9 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest5Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest5Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<6e6c389d54741d86e0a51358267c1b5d>> * @flow * @lightSyntaxTransform * @nogrep @@ -170,7 +170,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "eb95da17a46437e27a3ea0ccf845ea21"; + (node/*: any*/).hash = "204ef3451e43e60e858d6d974ae1ad2a"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest6Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest6Query.graphql.js index 3741f1ffa7973..8dc3dbc7e1656 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest6Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<295d4fe133262868316c6d296ed14ec2>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -156,7 +156,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "e8bc7d9a84fa2e9536aed16887b17a29"; + (node/*: any*/).hash = "f1d10f99d8e1782c2705acbf1604957e"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest9Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest9Query.graphql.js index ba00181e79d0a..9f10e8221e1b0 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest9Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTest9Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<416eb6b4ce3b9801bc42f80ee03261ad>> + * @generated SignedSource<<036174fe99b28ff7cb858124f057acdd>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "ae64013fff9f02d31b27ea607016ea03"; + (node/*: any*/).hash = "b046fd7374d1a7ea5d22b481c0edd547"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTestExecQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTestExecQuery.graphql.js new file mode 100644 index 0000000000000..af8b6bae7a707 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTestExecQuery.graphql.js @@ -0,0 +1,354 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<56932e6e8ce53b84765f1e82d2a18179>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ClientRequest, ClientQuery } from 'relay-runtime'; +import type { DataID } from "relay-runtime"; +import type { RelayReaderExecResolversTestUser____relay_model_instance$data } from "./RelayReaderExecResolversTestUser____relay_model_instance.graphql"; +import {RelayReaderExecResolversTest_user_one as queryRelayReaderExecResolversTestUserOneResolverType} from "../RelayReader-ExecResolvers-test.js"; +import type { TestResolverContextType } from "../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `queryRelayReaderExecResolversTestUserOneResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryRelayReaderExecResolversTestUserOneResolverType: ( + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {best_friend as relayReaderExecResolversTestUserBestFriendResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserBestFriendResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserBestFriendResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {name as relayReaderExecResolversTestUserNameResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserNameResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?string); +export type DataCheckerTestExecQuery$variables = {||}; +export type DataCheckerTestExecQuery$data = {| + +RelayReaderExecResolversTest_user_one: ?{| + +best_friend: ?{| + +best_friend: ?{| + +name: ?string, + |}, + +name: ?string, + |}, + +name: ?string, + |}, +|}; +export type DataCheckerTestExecQuery = {| + response: DataCheckerTestExecQuery$data, + variables: DataCheckerTestExecQuery$variables, +|}; +*/ + +var node/*: ClientRequest*/ = (function(){ +var v0 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser__id" +}, +v1 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser____relay_model_instance" +}, +v2 = { + "name": "name", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').name, + "rootFragment": null + } +}, +v3 = { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } +}, +v4 = { + "name": "best_friend", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').best_friend, + "rootFragment": null + } +}, +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "DataCheckerTestExecQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "path": "RelayReaderExecResolversTest_user_one" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.name" + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').best_friend, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.name" + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.best_friend.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').best_friend, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.best_friend" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.best_friend.name" + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "DataCheckerTestExecQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "RelayReaderExecResolversTest_user_one", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "rootFragment": null + } + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": (v3/*: any*/), + "backingField": (v4/*: any*/), + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": (v3/*: any*/), + "backingField": (v4/*: any*/), + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + (v2/*: any*/), + (v5/*: any*/) + ], + "storageKey": null + } + }, + (v5/*: any*/) + ], + "storageKey": null + } + }, + (v5/*: any*/) + ], + "storageKey": null + } + } + ], + "use_exec_time_resolvers": true + }, + "params": { + "cacheID": "a997fdfcc0dc79ab47ceea5ffbd6c1cc", + "id": null, + "metadata": {}, + "name": "DataCheckerTestExecQuery", + "operationKind": "query", + "text": null + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "c26914a95b9bc6165ea7513805119b77"; +} + +module.exports = ((node/*: any*/)/*: ClientQuery< + DataCheckerTestExecQuery$variables, + DataCheckerTestExecQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTestExecWithServerDataQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTestExecWithServerDataQuery.graphql.js new file mode 100644 index 0000000000000..8df35c8683acd --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/DataCheckerTestExecWithServerDataQuery.graphql.js @@ -0,0 +1,389 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<150bc702d604535148679ab06346bc70>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { DataID } from "relay-runtime"; +import type { RelayReaderExecResolversTestUser____relay_model_instance$data } from "./RelayReaderExecResolversTestUser____relay_model_instance.graphql"; +import {RelayReaderExecResolversTest_user_one as queryRelayReaderExecResolversTestUserOneResolverType} from "../RelayReader-ExecResolvers-test.js"; +import type { TestResolverContextType } from "../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `queryRelayReaderExecResolversTestUserOneResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryRelayReaderExecResolversTestUserOneResolverType: ( + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {best_friend as relayReaderExecResolversTestUserBestFriendResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserBestFriendResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserBestFriendResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {name as relayReaderExecResolversTestUserNameResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserNameResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?string); +export type DataCheckerTestExecWithServerDataQuery$variables = {||}; +export type DataCheckerTestExecWithServerDataQuery$data = {| + +RelayReaderExecResolversTest_user_one: ?{| + +best_friend: ?{| + +best_friend: ?{| + +name: ?string, + |}, + +name: ?string, + |}, + +name: ?string, + |}, + +me: ?{| + +name: ?string, + |}, +|}; +export type DataCheckerTestExecWithServerDataQuery = {| + response: DataCheckerTestExecWithServerDataQuery$data, + variables: DataCheckerTestExecWithServerDataQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser__id" +}, +v1 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser____relay_model_instance" +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v3 = { + "name": "name", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').name, + "rootFragment": null + } +}, +v4 = { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } +}, +v5 = { + "name": "best_friend", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').best_friend, + "rootFragment": null + } +}, +v6 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "DataCheckerTestExecWithServerDataQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "path": "RelayReaderExecResolversTest_user_one" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.name" + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').best_friend, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.name" + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.best_friend.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').best_friend, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.best_friend" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.best_friend.name" + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + }, + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + (v2/*: any*/) + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "DataCheckerTestExecWithServerDataQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "RelayReaderExecResolversTest_user_one", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "rootFragment": null + } + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": (v4/*: any*/), + "backingField": (v5/*: any*/), + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": (v4/*: any*/), + "backingField": (v5/*: any*/), + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + (v3/*: any*/), + (v6/*: any*/) + ], + "storageKey": null + } + }, + (v6/*: any*/) + ], + "storageKey": null + } + }, + (v6/*: any*/) + ], + "storageKey": null + } + }, + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + (v2/*: any*/), + (v6/*: any*/) + ], + "storageKey": null + } + ], + "use_exec_time_resolvers": true + }, + "params": { + "cacheID": "ff49275f22dc118a4a5554e2bb81b93a", + "id": null, + "metadata": {}, + "name": "DataCheckerTestExecWithServerDataQuery", + "operationKind": "query", + "text": "query DataCheckerTestExecWithServerDataQuery {\n me {\n name\n id\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "6e8ef036cc7105493415758b86368fe7"; +} + +module.exports = ((node/*: any*/)/*: Query< + DataCheckerTestExecWithServerDataQuery$variables, + DataCheckerTestExecWithServerDataQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestConditionQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestConditionQuery.graphql.js index a0062840650e7..0b942696dcaac 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestConditionQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestConditionQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<9eccd1713096134c15cd489f9e9fe697>> * @flow * @lightSyntaxTransform * @nogrep @@ -156,7 +156,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "6d02d262365a960c063af8b116377d2a"; + (node/*: any*/).hash = "43f766e8c0e9e4f2e6f15baa96299bd7"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadNoInlineQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadNoInlineQuery.graphql.js index e71d4311115e1..a5c372960777c 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadNoInlineQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadNoInlineQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<60953e8f5be888efc4ef6882def9344f>> * @flow * @lightSyntaxTransform * @nogrep @@ -116,7 +116,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "fbfe5e49950cb623a46a3c6e4377ee0c"; + (node/*: any*/).hash = "c757231a3cc1f2f44b4d7cee9b204962"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadQuery.graphql.js index a4f744cf9ac30..11f10dbc5eeec 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayExperimentalGraphResponseTransformTestFragmentSpreadQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<8d2c652e3c2d567f03599f65dc3440b9>> + * @generated SignedSource<<7b62202591e6eb6fbb653a813be7e9b1>> * @flow * @lightSyntaxTransform * @nogrep @@ -125,7 +125,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f90934a2aacb7ebd18141c401c9db833"; + (node/*: any*/).hash = "106c74251d41691aaeeadf9000b01b0b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentApplyMutationTest1Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentApplyMutationTest1Query.graphql.js index 35bee013f5508..072d07e9708b8 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentApplyMutationTest1Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentApplyMutationTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<24b2e65a3906df27c6360e61e8684c70>> + * @generated SignedSource<<1aec509db4488a518078481b3df62723>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "cae70132f7b7d25f52ad8f7c8aa563f2"; + (node/*: any*/).hash = "96c07bb47444d2b07d42e670403f73e1"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionAndRequiredTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionAndRequiredTestFeedbackQuery.graphql.js index 4341dea7d4267..7e46dbe28831e 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionAndRequiredTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionAndRequiredTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<482934cded369211b5d8c3468652e5d9>> * @flow * @lightSyntaxTransform * @nogrep @@ -219,7 +219,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "c71f667104383509795bb812551f3700"; + (node/*: any*/).hash = "97edae9a405d1bc18c11c249c60d9972"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestFeedbackQuery.graphql.js index 137e84746bc39..ea19b4e2a27bb 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<35bfd5bd4610bca89d68da74240b1135>> * @flow * @lightSyntaxTransform * @nogrep @@ -219,7 +219,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "2ab9d05a46f4c1a555cdbc247557cb8a"; + (node/*: any*/).hash = "4f550a20c8be8b72e6a11173729f2f0d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestPaginationQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestPaginationQuery.graphql.js index 832cfde5ad974..d8d731b2b53f2 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestPaginationQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentConnectionTestPaginationQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<1092790224fe96fae775da11bd2b74b7>> * @flow * @lightSyntaxTransform * @nogrep @@ -253,7 +253,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a076190aa4106d4efc94c7044acda9d3"; + (node/*: any*/).hash = "3c7371dcfecf7c2f23845a4381e25223"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestFeedbackQuery.graphql.js index f48ff1378f07b..12c98358d9d37 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<6df53546f89a0e3fe557a85da970ddde>> * @flow * @lightSyntaxTransform * @nogrep @@ -234,7 +234,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "93a8dd6942de5fbbc353f66e3f7d0dc6"; + (node/*: any*/).hash = "b57fa82fe4a28fee879d610ee77676d0"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestPaginationQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestPaginationQuery.graphql.js index 62297ac3da331..37f058999e043 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestPaginationQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentDynamicConnectionKeyTestPaginationQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<3f41e8f77728614235040452435a09e0>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -266,7 +266,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f1f26c129bc5e5ba17abf584fb161608"; + (node/*: any*/).hash = "2548fae49c8b458eaff80fd9f0b9fe02"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationTestCommentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationTestCommentQuery.graphql.js index 5f12a3417887f..8fd8233462f3e 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationTestCommentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<77de5013d91b19b8444a8a7e66ccbc54>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "cf4dd571769bdce0442d52bbcf1043b1"; + (node/*: any*/).hash = "525f90d51bcf7f9c6f2ee29ca2aee518"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithGlobalInvalidationTestCommentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithGlobalInvalidationTestCommentQuery.graphql.js index 314f32f77acd6..cc77228d615d5 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithGlobalInvalidationTestCommentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithGlobalInvalidationTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6cba849fbd6297647b406fe60c204681>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "7f5195e44dbcc52111a870ea10a689a9"; + (node/*: any*/).hash = "c1fd73322dacd90462ec736c1a7e75a4"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithLocalInvalidationTestCommentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithLocalInvalidationTestCommentQuery.graphql.js index 76f025d7c9806..ae9d7fcec8f11 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithLocalInvalidationTestCommentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithLocalInvalidationTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9f105fc814f498470d1e2aae145d616c>> + * @generated SignedSource<<0a5999522e6127ab9a1aab5f7468d7bb>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "7ea2a20a76665e224878c2c3c64ca7af"; + (node/*: any*/).hash = "01697c8ccf4980cfb1a655bad4327f7d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithMatchTestCommentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithMatchTestCommentQuery.graphql.js index 68c5c953d36f4..760258ffe56ec 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithMatchTestCommentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteMutationWithMatchTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<971fe46e359244d6b6f6b67ef992985e>> + * @generated SignedSource<<9f89469fc7b0e2e684fd5a8576302ccd>> * @flow * @lightSyntaxTransform * @nogrep @@ -199,7 +199,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "85aee16ac1e83847bd25d209521afc27"; + (node/*: any*/).hash = "4c4a8a3b814b6d49815f670d2296d1ff"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionTestCommentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionTestCommentQuery.graphql.js index 429fb6f64dfa0..c22a7febbbd9e 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionTestCommentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<72188650656e03e287d0ee66de681e42>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "19ec2bd10802d7b3486c8eacf7bc0e37"; + (node/*: any*/).hash = "0d4b8e1bf2b61e9a7c5c448f5737a807"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithDeferTestCommentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithDeferTestCommentQuery.graphql.js index 3f358063295dd..d97b2079bb423 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithDeferTestCommentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithDeferTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -160,7 +160,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "4e3ef6893b11d6b8e50305bb90fa383d"; + (node/*: any*/).hash = "8c04dd87122dd2f2e6d81c26c26b2e1e"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithMatchTestCommentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithMatchTestCommentQuery.graphql.js index be1655b720e85..5c2f644281113 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithMatchTestCommentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithMatchTestCommentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<37d87a29127c66506f4f587bbf3ce34b>> + * @generated SignedSource<<084c6feb9c37b0d0fcf2519ec85db7a9>> * @flow * @lightSyntaxTransform * @nogrep @@ -199,7 +199,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "aee303d0628e74c59aab556254f67057"; + (node/*: any*/).hash = "6867c6d5b6b3b26fbbd58906a450e38c"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithStreamTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithStreamTestFeedbackQuery.graphql.js index e05dc416273e8..ec1e6bf968b33 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithStreamTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteSubscriptionWithStreamTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<82a1b78ff2ee6768bd6e08fb87d7dd91>> * @flow * @lightSyntaxTransform * @nogrep @@ -167,7 +167,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "1e9ff23e175d055a8cf9262725de7afa"; + (node/*: any*/).hash = "6a889db656eb4f7bedb8485781900af3"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithCheckTestQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithCheckTestQuery.graphql.js new file mode 100644 index 0000000000000..94d47b93c7f98 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithCheckTestQuery.graphql.js @@ -0,0 +1,154 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<0b5f3fbd1ff42a527c41fa99087ac16c>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayModernEnvironmentExecuteWithCheckTestQuery$variables = {| + fetchSize: boolean, +|}; +export type RelayModernEnvironmentExecuteWithCheckTestQuery$data = {| + +me: ?{| + +name: ?string, + +profilePicture?: ?{| + +uri: ?string, + |}, + |}, +|}; +export type RelayModernEnvironmentExecuteWithCheckTestQuery = {| + response: RelayModernEnvironmentExecuteWithCheckTestQuery$data, + variables: RelayModernEnvironmentExecuteWithCheckTestQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "fetchSize" + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v2 = { + "condition": "fetchSize", + "kind": "Condition", + "passingValue": true, + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "size", + "value": 42 + } + ], + "concreteType": "Image", + "kind": "LinkedField", + "name": "profilePicture", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "uri", + "storageKey": null + } + ], + "storageKey": "profilePicture(size:42)" + } + ] +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "RelayModernEnvironmentExecuteWithCheckTestQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "RelayModernEnvironmentExecuteWithCheckTestQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "5dcc671b805f5953c02f9d662ee151ef", + "id": null, + "metadata": {}, + "name": "RelayModernEnvironmentExecuteWithCheckTestQuery", + "operationKind": "query", + "text": "query RelayModernEnvironmentExecuteWithCheckTestQuery(\n $fetchSize: Boolean!\n) {\n me {\n name\n profilePicture(size: 42) @include(if: $fetchSize) {\n uri\n }\n id\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "abc9670c9c2810d76f7450bfcf6cd79e"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayModernEnvironmentExecuteWithCheckTestQuery$variables, + RelayModernEnvironmentExecuteWithCheckTestQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithDeferTestUserQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithDeferTestUserQuery.graphql.js index a559e8ec7e470..6f5999cf5a115 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithDeferTestUserQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithDeferTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<357eaacf7dd0604d7eca85220fb4e66e>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -157,7 +157,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f0274d924fe95386193769563e6421fc"; + (node/*: any*/).hash = "79772170e0d7da0eac141c284c15e489"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithOverlappingStreamTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithOverlappingStreamTestFeedbackQuery.graphql.js index f1068ba8d697b..e2971df6b8aa1 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithOverlappingStreamTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithOverlappingStreamTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -218,7 +218,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f23e7dbdffffaa06c49725c9cceca25c"; + (node/*: any*/).hash = "06b066155ac2bffd6466e49b3836ff99"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgManyFragmentsQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgManyFragmentsQuery.graphql.js index 8fd77d65ae7f1..f23a72cecb284 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgManyFragmentsQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgManyFragmentsQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6713b0a8e08ed95789878b165ffac985>> + * @generated SignedSource<<406c068f2bba084f29b0910124606e25>> * @flow * @lightSyntaxTransform * @nogrep @@ -236,7 +236,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "354b41b8063702301345c74af4c434f7"; + (node/*: any*/).hash = "27f90d252de1907833b6031e90a40707"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgSingleFragmentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgSingleFragmentQuery.graphql.js index f426f2dc21593..600d28cc8782b 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgSingleFragmentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithProvidedVariableTest_UserArgSingleFragmentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<202e4fac8401882f52063c14c4da0afc>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -190,7 +190,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "28c63ee2f6ef93b2c67bcded12b3940e"; + (node/*: any*/).hash = "ceb095ac103f8ed7a4155eead5586b81"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamAndRequiredTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamAndRequiredTestFeedbackQuery.graphql.js index 912966a25d108..e4c952fcc80f3 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamAndRequiredTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamAndRequiredTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9c52616bbf6a11a2378e9570663828c2>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -166,7 +166,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "ab3c3dfb9f6ec864b836f85e13609fb0"; + (node/*: any*/).hash = "0eb364a40bfac00046a99af9460d1057"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamTestFeedbackQuery.graphql.js index 432c21d129d59..d27fd3190c73a 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<82b783bb63411bd4c967ef938e0e55a6>> * @flow * @lightSyntaxTransform * @nogrep @@ -175,7 +175,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "91e0270ce8d4cdca76615d176c0e0c7c"; + (node/*: any*/).hash = "f5dbd4f27aae2c8c13d4b0978ad92446"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamWithHandlerTestFeedbackQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamWithHandlerTestFeedbackQuery.graphql.js index 5f8db36e99486..04e97b9960bb1 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamWithHandlerTestFeedbackQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithStreamWithHandlerTestFeedbackQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<1a0084c00b0e1e4c5f8db223a8ff72a3>> * @flow * @lightSyntaxTransform * @nogrep @@ -184,7 +184,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "448b460c0771d55eb7b0ec5c53bd1c59"; + (node/*: any*/).hash = "02faeaf93f1d34d7ca7c354c522426cd"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithUndeclaredUnusedArgumentTestQueryWithUnusedFragmentArgumentDefinitionQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithUndeclaredUnusedArgumentTestQueryWithUnusedFragmentArgumentDefinitionQuery.graphql.js index 34a30c7d7d01b..cd1ffb2d12ab9 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithUndeclaredUnusedArgumentTestQueryWithUnusedFragmentArgumentDefinitionQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithUndeclaredUnusedArgumentTestQueryWithUnusedFragmentArgumentDefinitionQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<5730f1912881607dacef35d4a8046c40>> * @flow * @lightSyntaxTransform * @nogrep @@ -160,7 +160,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "00358e8069835783f936954905b1cf85"; + (node/*: any*/).hash = "fc8a112e7a02ef04ca3b597f2095096d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestStreamQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestStreamQuery.graphql.js index 6cd72b13aba9d..e0ad83cf86e92 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestStreamQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestStreamQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<191b4e64f5bfa318669814916590702d>> * @flow * @lightSyntaxTransform * @nogrep @@ -137,7 +137,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "07e00f103682c152c4770a0e200cd6e7"; + (node/*: any*/).hash = "ef3b0ee1286de679a140741dc9baed1d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline$normalization.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline$normalization.graphql.js index cdaccd4e2fab1..4dab6e5aa66a1 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline$normalization.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline$normalization.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<87f1ddb67fbaba61b623b5fa008cafab>> * @flow * @lightSyntaxTransform * @nogrep @@ -113,7 +113,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "8541107c8da22deef0a7e355409ab1d0"; + (node/*: any*/).hash = "c176d8758682964446ea51b58b3a3f76"; } module.exports = node; diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline.graphql.js index 572234fa02960..d736e2940adb2 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTestWithArgs_noInline.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<5f4b6a1cbab020dbfb770b817af05746>> + * @generated SignedSource<<9355ef70efb895879886c3eefbbb8e36>> * @flow * @lightSyntaxTransform * @nogrep @@ -127,7 +127,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "8541107c8da22deef0a7e355409ab1d0"; + (node/*: any*/).hash = "c176d8758682964446ea51b58b3a3f76"; } module.exports = ((node/*: any*/)/*: Fragment< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent$normalization.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent$normalization.graphql.js index cc6d513438dc6..8734627e0118b 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent$normalization.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent$normalization.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<1f1eaaa0873019c487ebbca315662cd4>> + * @generated SignedSource<<933cf55a67414825e194a14592aaee42>> * @flow * @lightSyntaxTransform * @nogrep @@ -143,7 +143,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "d674bb7d0e482ecdd681a2e8574ff5fe"; + (node/*: any*/).hash = "80e0fda8b8d8bb4e7200ea5387229c4c"; } module.exports = node; diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent.graphql.js index 64d1db3cab621..3d8e35bbad772 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_nestedNoInlineParent.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<97802b4904faf63be406cd26668c8d35>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -146,7 +146,7 @@ var node/*: ReaderFragment*/ = { }; if (__DEV__) { - (node/*: any*/).hash = "d674bb7d0e482ecdd681a2e8574ff5fe"; + (node/*: any*/).hash = "80e0fda8b8d8bb4e7200ea5387229c4c"; } module.exports = ((node/*: any*/)/*: Fragment< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline$normalization.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline$normalization.graphql.js index 8efb5f04dba04..0e4aae4af33d1 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline$normalization.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline$normalization.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<4ad9e981e86b2be0673b5e990a0ae87d>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -94,7 +94,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "6bd80bb9c64c065763c7ddc0ef046c62"; + (node/*: any*/).hash = "e69851050102bb98a80e11aa48993f20"; } module.exports = node; diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline.graphql.js index 774f131aecf6f..f86ba161c5b50 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentNoInlineTest_noInline.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -117,7 +117,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "6bd80bb9c64c065763c7ddc0ef046c62"; + (node/*: any*/).hash = "e69851050102bb98a80e11aa48993f20"; } module.exports = ((node/*: any*/)/*: Fragment< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery.graphql.js new file mode 100644 index 0000000000000..8e04259baef57 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery.graphql.js @@ -0,0 +1,124 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$fragmentType } from "./RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment.graphql"; +export type RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery$variables = {||}; +export type RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery$data = {| + +me: ?{| + +$fragmentSpreads: RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$fragmentType, + |}, +|}; +export type RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery = {| + response: RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery$data, + variables: RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "name": "age", + "args": null, + "fragment": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "c498bb05241f280bc2224c29335322d9", + "id": null, + "metadata": {}, + "name": "RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery", + "operationKind": "query", + "text": "query RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery {\n me {\n ...RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment\n id\n }\n}\n\nfragment RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment on User {\n id\n name\n}\n" + } +}; + +if (__DEV__) { + (node/*: any*/).hash = "51bb39abe5fa87455d7805c59b5def94"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery$variables, + RelayModernEnvironmentSubscriptionWithResolverContextTestParentQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment.graphql.js new file mode 100644 index 0000000000000..1bb2d52b8cb73 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment.graphql.js @@ -0,0 +1,90 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +import {age as userAgeResolverType} from "../resolvers/UserAgeResolvers.js"; +import type { TestResolverContextType } from "../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `userAgeResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userAgeResolverType: ( + args: void, + context: TestResolverContextType, +) => ?number); +declare export opaque type RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$fragmentType: FragmentType; +export type RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$data = {| + +age: ?number, + +id: string, + +name: ?string, + +$fragmentType: RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$fragmentType, +|}; +export type RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$key = { + +$data?: RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$data, + +$fragmentSpreads: RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayResolver", + "name": "age", + "resolverModule": require('./../resolvers/UserAgeResolvers').age, + "path": "age" + } + ] + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "66a7aeaa5486c95229787503c12b1aa0"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$fragmentType, + RelayModernEnvironmentSubscriptionWithResolverContextTestUserFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest2Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest2Query.graphql.js index 62fc2496a1d2a..5938104634e5a 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest2Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest2Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<3ead466eab2ca6cd7f6c2bac7cc3dac9>> + * @generated SignedSource<<82d72327169930be140c163243815eb3>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "4deb6feeb5af2831d313645105f8165c"; + (node/*: any*/).hash = "1fab375c7c967318ceb32778cf782bd9"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest3Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest3Query.graphql.js index 76e6fc11da654..a54a6d50335b4 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest3Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest3Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<558eb35151893792bd27750bc3121534>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "69d71c1ff828bb46f4cd52ffb90e99fa"; + (node/*: any*/).hash = "c564d7a87f1534ebaab63cb02181ea1d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest4Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest4Query.graphql.js index 9fde344b0acaa..56e9f3c0e10c9 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest4Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest4Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<401f3ba45f54554d399a07a8b989acdd>> * @flow * @lightSyntaxTransform * @nogrep @@ -155,7 +155,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a58fd2e641e7c6652209199221c50e34"; + (node/*: any*/).hash = "73a67c0a4ac2f622587eea77a3a86f76"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Fragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Fragment.graphql.js index 68dad5ea28f02..a78e5a8348b82 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Fragment.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Fragment.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -65,7 +65,7 @@ var node/*: ReaderFragment*/ = { }; if (__DEV__) { - (node/*: any*/).hash = "96697de654c1f1d642048b41e5eaa8c7"; + (node/*: any*/).hash = "356c08c8ef540e0358e184a181394edc"; } module.exports = ((node/*: any*/)/*: Fragment< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Query.graphql.js index 92b8ad1068c43..d862766b94d07 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest5Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9d79c27b86f19bbabd551680392a8e54>> + * @generated SignedSource<<5dbfe9a1ca28a6e36ee7f05b2f4717f3>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "44a6f6a48ad431517c8ff66ac7b1e475"; + (node/*: any*/).hash = "550955aca4916dc529f623ad058f3149"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest6Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest6Query.graphql.js index 524d3e5a2fc59..0d5549fe11039 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest6Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -155,7 +155,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "8a7b0811d0016fa43cbdb871c6825a8e"; + (node/*: any*/).hash = "019de924708dbca8b54a4b8760c50998"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest9Fragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest9Fragment.graphql.js index 098d5e9f8b350..220212c377b5c 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest9Fragment.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTest9Fragment.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<735f291c29b9a6f94a0818606b6d033d>> + * @generated SignedSource<<1fac305c2c65adfa6d0349805dfd6b5c>> * @flow * @lightSyntaxTransform * @nogrep @@ -65,7 +65,7 @@ var node/*: ReaderFragment*/ = { }; if (__DEV__) { - (node/*: any*/).hash = "7006df6bd31b24b2a89e742500e6165a"; + (node/*: any*/).hash = "eb358a93c13d1baeb0a769c284f8b440"; } module.exports = ((node/*: any*/)/*: Fragment< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestAbstractQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestAbstractQuery.graphql.js index 232bce9e28be4..396f9a7cb6a3d 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestAbstractQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestAbstractQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<3c0e836b2db9f6c315ac20f510f0d014>> + * @generated SignedSource<<85d7cecfc3bb841c247b5d2fd950cab7>> * @flow * @lightSyntaxTransform * @nogrep @@ -147,7 +147,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "aff59a67ff8458a227e246a603d9ee26"; + (node/*: any*/).hash = "8035321d8e2ae9f9cb97b1d0deca22d6"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestConcreteQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestConcreteQuery.graphql.js index dddec4ac8867f..9a17a54876bfb 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestConcreteQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestConcreteQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<52d1dc3f0bfcbd2c058cf348b1bfe165>> + * @generated SignedSource<<7d64ac33464a98083aa1105f78eff313>> * @flow * @lightSyntaxTransform * @nogrep @@ -147,7 +147,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "08f8aa409b7c457e4992582d6eb9d7a5"; + (node/*: any*/).hash = "9a839040e1d7a6501f9080b5b8ff38db"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestParentQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestParentQuery.graphql.js index 06be6b006b547..dcf93ac30459b 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestParentQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentTypeRefinementTestParentQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<75f751c4837ec6f4b06ff7391619f1f4>> * @flow * @lightSyntaxTransform * @nogrep @@ -177,7 +177,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "689f4ef00bbe32b65200f7bf0b18600d"; + (node/*: any*/).hash = "d976516696559b4da133ef37cf797609"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentWithOperationTrackerTestQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentWithOperationTrackerTestQuery.graphql.js index badc8f111ad23..46f44c63b2d8e 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentWithOperationTrackerTestQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentWithOperationTrackerTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<0bd821834d2425699b7cf0ece8c733ff>> + * @generated SignedSource<<646d5dd7a58d8d074c1ea4c14a3d3544>> * @flow * @lightSyntaxTransform * @nogrep @@ -327,7 +327,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a7167fdd5f3eacc9c1ed47a342eb2fa0"; + (node/*: any*/).hash = "f99896bd25a8f9b54139a54ecb15defe"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldNoLoggerTestUserQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldNoLoggerTestUserQuery.graphql.js index 552872750afa7..3fcadb326666c 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldNoLoggerTestUserQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldNoLoggerTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<2f3f8c1a93cfc0e00653aa88cfb1d550>> + * @generated SignedSource<<133c9604c3033d80c01c583ce030b26d>> * @flow * @lightSyntaxTransform * @nogrep @@ -134,7 +134,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "509d57fcdf4027461a38077ba36fc41b"; + (node/*: any*/).hash = "5772f2b553a33bce8df54b6f1c7032ae"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldTestUserQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldTestUserQuery.graphql.js index c65ee991c98c8..0bf63d9cc77b5 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldTestUserQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverRequiredFieldTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<169fc6b05f4f8676b7309e500241dd89>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -141,7 +141,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "7a8f1c7d05c71461bd82aa5538c96b3c"; + (node/*: any*/).hash = "624e9bc603f1fb6687879a87884278c8"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestAffectingQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestAffectingQuery.graphql.js index 1ff5d00455d84..990103252eaf7 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestAffectingQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestAffectingQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<4c8f71814d406e87ff29593bc0a61082>> * @flow * @lightSyntaxTransform * @nogrep @@ -189,7 +189,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "ded358125ddc82c32d526451fd5f1a0e"; + (node/*: any*/).hash = "503f6130ff2642a6155862ad71840e2b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestQuery.graphql.js index c6fbacb14a8f5..ee0ac4c82477f 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<95f7085fa90bf1186a200e4bb7a0bd75>> * @flow * @lightSyntaxTransform * @nogrep @@ -189,7 +189,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "861d571e1856374cfbff7ce6564c306c"; + (node/*: any*/).hash = "927b2880628e050a5b8104216923a40b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverWithFragmentOwnershipTestUserQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverWithFragmentOwnershipTestUserQuery.graphql.js index 85080688c6b07..6a2eb6b015e41 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverWithFragmentOwnershipTestUserQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernFragmentSpecResolverWithFragmentOwnershipTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<7c26cc8690db0d9e24fe78d43eabfeb3>> + * @generated SignedSource<<1e7d62a97f7fd9493e545e9da3dfb270>> * @flow * @lightSyntaxTransform * @nogrep @@ -196,7 +196,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "0ac3466c6ebc673ebbcfbbf5e1fead2b"; + (node/*: any*/).hash = "011f30616d7a8c12b013883ec537f28c"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernSelectorTestUserQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernSelectorTestUserQuery.graphql.js index df98e5cad3e78..78bd9899201d2 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernSelectorTestUserQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernSelectorTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<6e1039059f1c88ea8e6e5c3c64cbec32>> * @flow * @lightSyntaxTransform * @nogrep @@ -189,7 +189,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "afbaf504a28e027de34401ff4a82e567"; + (node/*: any*/).hash = "56dee97a569ea3090f0026337129c6e2"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest1Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest1Query.graphql.js index d4be05a2cd896..05ec0fbe6df33 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest1Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<8645349c6f6b388cf6aca8ae954919b8>> + * @generated SignedSource<<4e75eb0df9c99a7434eabf7ff7db7942>> * @flow * @lightSyntaxTransform * @nogrep @@ -164,7 +164,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "7fdabede719577afaae8855a27396b98"; + (node/*: any*/).hash = "04b19cd56ddc2656fb74b7223e570e06"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest6Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest6Query.graphql.js index 1e79b634b4d17..e0d8dce0c0b84 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest6Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<39f352fd5b09c8333f7f007876341503>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -164,7 +164,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "c84a88e1af0fcca4eb3739581f34d286"; + (node/*: any*/).hash = "f080f5a0fc584f99ea0b4d1bbff0d87f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest7Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest7Query.graphql.js index 39e96bb29a481..bda7411dfb383 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest7Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest7Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<1098cb2a455fdad1e5a6cd753dab70f3>> + * @generated SignedSource<<97892b0488c3259e6b5c855efa860d6c>> * @flow * @lightSyntaxTransform * @nogrep @@ -164,7 +164,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "2bfbf713695a9ce69b8e915e0ec020f4"; + (node/*: any*/).hash = "8de95361d09966d41d9b73fad489d534"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest9Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest9Query.graphql.js index 3fae0521cd84b..3b23ac27643b4 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest9Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayModernStoreTest9Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -164,7 +164,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "7ae41adfd80d75a8e28e02f6df5baf47"; + (node/*: any*/).hash = "b32973d64f3cb9d3955e0aab2c9a36f2"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestClientDirectiveQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestClientDirectiveQuery.graphql.js new file mode 100644 index 0000000000000..2db8fc7fc3b7a --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestClientDirectiveQuery.graphql.js @@ -0,0 +1,408 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ClientRequest, ClientQuery } from 'relay-runtime'; +import type { DataID } from "relay-runtime"; +import type { RelayReaderExecResolversTestUser____relay_model_instance$data } from "./RelayReaderExecResolversTestUser____relay_model_instance.graphql"; +import {RelayReaderExecResolversTest_user_one as queryRelayReaderExecResolversTestUserOneResolverType} from "../RelayReader-ExecResolvers-test.js"; +import type { TestResolverContextType } from "../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `queryRelayReaderExecResolversTestUserOneResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryRelayReaderExecResolversTestUserOneResolverType: ( + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {best_friend as relayReaderExecResolversTestUserBestFriendResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserBestFriendResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserBestFriendResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {friends as relayReaderExecResolversTestUserFriendsResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserFriendsResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserFriendsResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?$ReadOnlyArray); +import {name as relayReaderExecResolversTestUserNameResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserNameResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?string); +export type RelayReaderExecResolversTestClientDirectiveQuery$variables = {||}; +export type RelayReaderExecResolversTestClientDirectiveQuery$data = {| + +RelayReaderExecResolversTest_user_one: ?{| + +best_friend: ?{| + +name: ?string, + |}, + +friends: ?$ReadOnlyArray, + +name: $NonMaybeType, + |}, +|}; +export type RelayReaderExecResolversTestClientDirectiveQuery = {| + response: RelayReaderExecResolversTestClientDirectiveQuery$data, + variables: RelayReaderExecResolversTestClientDirectiveQuery$variables, +|}; +*/ + +var node/*: ClientRequest*/ = (function(){ +var v0 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser__id" +}, +v1 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser____relay_model_instance" +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "kind": "InlineFragment", + "selections": [ + { + "name": "__relay_model_instance", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, + "rootFragment": null + }, + "fragment": { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/) + ], + "type": "RelayReaderExecResolversTestUser", + "abstractKey": null + } + } + ], + "type": "RelayReaderExecResolversTestUser", + "abstractKey": null +}, +v4 = { + "name": "name", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').name, + "rootFragment": null + }, + "fragment": (v3/*: any*/) +}, +v5 = [ + (v4/*: any*/), + (v2/*: any*/) +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "RelayReaderExecResolversTestClientDirectiveQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "path": "RelayReaderExecResolversTest_user_one" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + { + "kind": "RequiredField", + "field": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.name" + }, + "action": "THROW" + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').best_friend, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.name" + } + ], + "storageKey": null + } + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "friends", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.friends.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "friends", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').friends, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.friends" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "friends", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.friends.name" + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayReaderExecResolversTestClientDirectiveQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "RelayReaderExecResolversTest_user_one", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "rootFragment": null + }, + "fragment": null + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + (v4/*: any*/), + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "best_friend", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').best_friend, + "rootFragment": null + }, + "fragment": (v3/*: any*/) + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": (v5/*: any*/), + "storageKey": null + } + }, + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "friends", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').friends, + "rootFragment": null + }, + "fragment": (v3/*: any*/) + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "friends", + "plural": true, + "selections": (v5/*: any*/), + "storageKey": null + } + }, + (v2/*: any*/) + ], + "storageKey": null + } + } + ], + "exec_time_resolvers_enabled_provider": require('./../relayReaderTestExecTimeResolversTrueProvider') + }, + "params": { + "cacheID": "93766bd16ee00d3863eac4f5873050f1", + "id": null, + "metadata": {}, + "name": "RelayReaderExecResolversTestClientDirectiveQuery", + "operationKind": "query", + "text": null + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "6a6cebf94e46a5bc998e01e8c6a67718"; +} + +module.exports = ((node/*: any*/)/*: ClientQuery< + RelayReaderExecResolversTestClientDirectiveQuery$variables, + RelayReaderExecResolversTestClientDirectiveQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestFalseProviderQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestFalseProviderQuery.graphql.js new file mode 100644 index 0000000000000..a7e25d3c38179 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestFalseProviderQuery.graphql.js @@ -0,0 +1,404 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<6d0bfb40c19700da1455005994693e24>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ClientRequest, ClientQuery } from 'relay-runtime'; +import type { DataID } from "relay-runtime"; +import type { RelayReaderExecResolversTestUser____relay_model_instance$data } from "./RelayReaderExecResolversTestUser____relay_model_instance.graphql"; +import {RelayReaderExecResolversTest_user_one as queryRelayReaderExecResolversTestUserOneResolverType} from "../RelayReader-ExecResolvers-test.js"; +import type { TestResolverContextType } from "../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `queryRelayReaderExecResolversTestUserOneResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryRelayReaderExecResolversTestUserOneResolverType: ( + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {best_friend as relayReaderExecResolversTestUserBestFriendResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserBestFriendResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserBestFriendResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?{| + +id: DataID, +|}); +import {friends as relayReaderExecResolversTestUserFriendsResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserFriendsResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserFriendsResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?$ReadOnlyArray); +import {name as relayReaderExecResolversTestUserNameResolverType} from "../RelayReader-ExecResolvers-test.js"; +// Type assertion validating that `relayReaderExecResolversTestUserNameResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(relayReaderExecResolversTestUserNameResolverType: ( + __relay_model_instance: RelayReaderExecResolversTestUser____relay_model_instance$data['__relay_model_instance'], + args: void, + context: TestResolverContextType, +) => ?string); +export type RelayReaderExecResolversTestFalseProviderQuery$variables = {||}; +export type RelayReaderExecResolversTestFalseProviderQuery$data = {| + +RelayReaderExecResolversTest_user_one: ?{| + +best_friend: ?{| + +name: ?string, + |}, + +friends: ?$ReadOnlyArray, + +name: ?string, + |}, +|}; +export type RelayReaderExecResolversTestFalseProviderQuery = {| + response: RelayReaderExecResolversTestFalseProviderQuery$data, + variables: RelayReaderExecResolversTestFalseProviderQuery$variables, +|}; +*/ + +var node/*: ClientRequest*/ = (function(){ +var v0 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser__id" +}, +v1 = { + "args": null, + "kind": "FragmentSpread", + "name": "RelayReaderExecResolversTestUser____relay_model_instance" +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "kind": "InlineFragment", + "selections": [ + { + "name": "__relay_model_instance", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, + "rootFragment": null + }, + "fragment": { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/) + ], + "type": "RelayReaderExecResolversTestUser", + "abstractKey": null + } + } + ], + "type": "RelayReaderExecResolversTestUser", + "abstractKey": null +}, +v4 = { + "name": "name", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').name, + "rootFragment": null + }, + "fragment": (v3/*: any*/) +}, +v5 = [ + (v4/*: any*/), + (v2/*: any*/) +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "RelayReaderExecResolversTestFalseProviderQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayResolver", + "name": "RelayReaderExecResolversTest_user_one", + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "path": "RelayReaderExecResolversTest_user_one" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.name" + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "best_friend", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').best_friend, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.best_friend.name" + } + ], + "storageKey": null + } + }, + { + "kind": "ClientEdgeToClientObject", + "concreteType": "RelayReaderExecResolversTestUser", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "alias": null, + "args": null, + "fragment": (v0/*: any*/), + "kind": "RelayResolver", + "name": "friends", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser__id.graphql'), require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, 'id', true), + "path": "RelayReaderExecResolversTest_user_one.friends.__relay_model_instance" + } + }, + "backingField": { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "friends", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').friends, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.friends" + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "friends", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "fragment": (v1/*: any*/), + "kind": "RelayResolver", + "name": "name", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('./RelayReaderExecResolversTestUser____relay_model_instance.graphql'), require('./../RelayReader-ExecResolvers-test').name, '__relay_model_instance', true), + "path": "RelayReaderExecResolversTest_user_one.friends.name" + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayReaderExecResolversTestFalseProviderQuery", + "selections": [ + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "RelayReaderExecResolversTest_user_one", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, + "rootFragment": null + }, + "fragment": null + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "RelayReaderExecResolversTest_user_one", + "plural": false, + "selections": [ + (v4/*: any*/), + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "best_friend", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').best_friend, + "rootFragment": null + }, + "fragment": (v3/*: any*/) + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "best_friend", + "plural": false, + "selections": (v5/*: any*/), + "storageKey": null + } + }, + { + "kind": "ClientEdgeToClientObject", + "modelResolvers": { + "RelayReaderExecResolversTestUser": { + "resolverModule": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser + } + }, + "backingField": { + "name": "friends", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').friends, + "rootFragment": null + }, + "fragment": (v3/*: any*/) + }, + "linkedField": { + "alias": null, + "args": null, + "concreteType": "RelayReaderExecResolversTestUser", + "kind": "LinkedField", + "name": "friends", + "plural": true, + "selections": (v5/*: any*/), + "storageKey": null + } + }, + (v2/*: any*/) + ], + "storageKey": null + } + } + ], + "exec_time_resolvers_enabled_provider": require('./../relayReaderTestExecTimeResolversFalseProvider') + }, + "params": { + "cacheID": "5b04e4ba9c8655b7b3a2cbce5a48eea8", + "id": null, + "metadata": {}, + "name": "RelayReaderExecResolversTestFalseProviderQuery", + "operationKind": "query", + "text": null + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "ecae75fae0ced72851da368b4e1e828d"; +} + +module.exports = ((node/*: any*/)/*: ClientQuery< + RelayReaderExecResolversTestFalseProviderQuery$variables, + RelayReaderExecResolversTestFalseProviderQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestRunsQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestQuery.graphql.js similarity index 88% rename from packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestRunsQuery.graphql.js rename to packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestQuery.graphql.js index 3fed50cb4c71d..d2c311fe03734 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestRunsQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderExecResolversTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -58,8 +58,8 @@ import {name as relayReaderExecResolversTestUserNameResolverType} from "../Relay args: void, context: TestResolverContextType, ) => ?string); -export type RelayReaderExecResolversTestRunsQuery$variables = {||}; -export type RelayReaderExecResolversTestRunsQuery$data = {| +export type RelayReaderExecResolversTestQuery$variables = {||}; +export type RelayReaderExecResolversTestQuery$data = {| +RelayReaderExecResolversTest_user_one: ?{| +best_friend: ?{| +name: ?string, @@ -70,9 +70,9 @@ export type RelayReaderExecResolversTestRunsQuery$data = {| +name: ?string, |}, |}; -export type RelayReaderExecResolversTestRunsQuery = {| - response: RelayReaderExecResolversTestRunsQuery$data, - variables: RelayReaderExecResolversTestRunsQuery$variables, +export type RelayReaderExecResolversTestQuery = {| + response: RelayReaderExecResolversTestQuery$data, + variables: RelayReaderExecResolversTestQuery$variables, |}; */ @@ -88,6 +88,39 @@ v1 = { "name": "RelayReaderExecResolversTestUser____relay_model_instance" }, v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "kind": "InlineFragment", + "selections": [ + { + "name": "__relay_model_instance", + "args": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": false, + "resolverInfo": { + "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTestUser, + "rootFragment": null + }, + "fragment": { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/) + ], + "type": "RelayReaderExecResolversTestUser", + "abstractKey": null + } + } + ], + "type": "RelayReaderExecResolversTestUser", + "abstractKey": null +}, +v4 = { "name": "name", "args": null, "kind": "RelayResolver", @@ -96,18 +129,12 @@ v2 = { "resolverInfo": { "resolverFunction": require('./../RelayReader-ExecResolvers-test').name, "rootFragment": null - } -}, -v3 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null + }, + "fragment": (v3/*: any*/) }, -v4 = [ - (v2/*: any*/), - (v3/*: any*/) +v5 = [ + (v4/*: any*/), + (v2/*: any*/) ]; return { "fragment": { @@ -116,7 +143,7 @@ return { "metadata": { "hasClientEdges": true }, - "name": "RelayReaderExecResolversTestRunsQuery", + "name": "RelayReaderExecResolversTestQuery", "selections": [ { "kind": "ClientEdgeToClientObject", @@ -258,7 +285,7 @@ return { "operation": { "argumentDefinitions": [], "kind": "Operation", - "name": "RelayReaderExecResolversTestRunsQuery", + "name": "RelayReaderExecResolversTestQuery", "selections": [ { "kind": "ClientEdgeToClientObject", @@ -276,7 +303,8 @@ return { "resolverInfo": { "resolverFunction": require('./../RelayReader-ExecResolvers-test').RelayReaderExecResolversTest_user_one, "rootFragment": null - } + }, + "fragment": null }, "linkedField": { "alias": null, @@ -286,7 +314,7 @@ return { "name": "RelayReaderExecResolversTest_user_one", "plural": false, "selections": [ - (v2/*: any*/), + (v4/*: any*/), { "kind": "ClientEdgeToClientObject", "modelResolvers": { @@ -303,7 +331,8 @@ return { "resolverInfo": { "resolverFunction": require('./../RelayReader-ExecResolvers-test').best_friend, "rootFragment": null - } + }, + "fragment": (v3/*: any*/) }, "linkedField": { "alias": null, @@ -312,7 +341,7 @@ return { "kind": "LinkedField", "name": "best_friend", "plural": false, - "selections": (v4/*: any*/), + "selections": (v5/*: any*/), "storageKey": null } }, @@ -332,7 +361,8 @@ return { "resolverInfo": { "resolverFunction": require('./../RelayReader-ExecResolvers-test').friends, "rootFragment": null - } + }, + "fragment": (v3/*: any*/) }, "linkedField": { "alias": null, @@ -341,23 +371,23 @@ return { "kind": "LinkedField", "name": "friends", "plural": true, - "selections": (v4/*: any*/), + "selections": (v5/*: any*/), "storageKey": null } }, - (v3/*: any*/) + (v2/*: any*/) ], "storageKey": null } } ], - "use_exec_time_resolvers": true + "exec_time_resolvers_enabled_provider": require('./../relayReaderTestExecTimeResolversTrueProvider') }, "params": { - "cacheID": "3f73e57d52c3f79eecc247feb0f865c5", + "cacheID": "bd1a2a7e4d80e5e5a017a7ff107bd87f", "id": null, "metadata": {}, - "name": "RelayReaderExecResolversTestRunsQuery", + "name": "RelayReaderExecResolversTestQuery", "operationKind": "query", "text": null } @@ -365,10 +395,10 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "578779b7fde7d06fa0d924a675453176"; + (node/*: any*/).hash = "de0d2442f1700c6fe635c62a4d645b91"; } module.exports = ((node/*: any*/)/*: ClientQuery< - RelayReaderExecResolversTestRunsQuery$variables, - RelayReaderExecResolversTestRunsQuery$data, + RelayReaderExecResolversTestQuery$variables, + RelayReaderExecResolversTestQuery$data, >*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..c6b07289258b1 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,152 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<520b92b838637598ce6b190feda24304>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery$variables = {||}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery$data = {| + +node: ?{| + +__typename: string, + +friends?: ?{| + +edges: ?$ReadOnlyArray, + |}, + +id: string, + |}, +|}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery = {| + response: RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery$data, + variables: RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "id", + "value": "1" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 3 + } + ], + "concreteType": "FriendsConnection", + "kind": "LinkedField", + "name": "friends", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "FriendsEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "friends(first:3)" + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": "node(id:\"1\")" + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "throwOnFieldError": true + }, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery", + "selections": (v0/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "b4e49b016710bab100689bfb7b5fd99a", + "id": null, + "metadata": {}, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery {\n node(id: \"1\") {\n id\n __typename\n ... on User {\n friends(first: 3) {\n edges {\n cursor\n }\n }\n }\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "f545f883732869b6e4527c5f09a6b5eb"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery$variables, + RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..5db2b2bc612b1 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,150 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<2c4e7ac15042028a5c73454531cbb12b>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery$variables = {||}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery$data = {| + +node: ?{| + +__typename: string, + +friends?: ?{| + +edges: ?$ReadOnlyArray, + |}, + +id: string, + |}, +|}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery = {| + response: RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery$data, + variables: RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "id", + "value": "1" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 3 + } + ], + "concreteType": "FriendsConnection", + "kind": "LinkedField", + "name": "friends", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "FriendsEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "friends(first:3)" + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": "node(id:\"1\")" + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery", + "selections": (v0/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "9bcd1fa083106133acd9429ae203b4c6", + "id": null, + "metadata": {}, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery {\n node(id: \"1\") {\n id\n __typename\n ... on User {\n friends(first: 3) {\n edges {\n cursor\n }\n }\n }\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "f4834de5be0525aba139b83eb190e02f"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery$variables, + RelayReaderRelayErrorHandlingTestNoncompliantEmptyLinkedFieldWithoutThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..a8ec8384776a7 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,120 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<7d7421d8f95edf6cade0e79bbabb6616>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery$variables = {||}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery$data = {| + +node: ?{| + +__typename: string, + +emailAddresses?: ?$ReadOnlyArray, + +id: string, + |}, +|}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery = {| + response: RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery$data, + variables: RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "id", + "value": "1" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "emailAddresses", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": "node(id:\"1\")" + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "throwOnFieldError": true + }, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery", + "selections": (v0/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "2f8f0fea05a87b91ed80d5f62dd9308c", + "id": null, + "metadata": {}, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery {\n node(id: \"1\") {\n id\n __typename\n ... on User {\n emailAddresses\n }\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "39bcfd3ec0582f9ae2c60746ee9c98a3"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery$variables, + RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..e9908223116f6 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,118 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<515ab98f99462586696aee002f3bf31f>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery$variables = {||}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery$data = {| + +node: ?{| + +__typename: string, + +emailAddresses?: ?$ReadOnlyArray, + +id: string, + |}, +|}; +export type RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery = {| + response: RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery$data, + variables: RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "id", + "value": "1" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "emailAddresses", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": "node(id:\"1\")" + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery", + "selections": (v0/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "a278c7d054186ae97ab78b656d9a57c6", + "id": null, + "metadata": {}, + "name": "RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery {\n node(id: \"1\") {\n id\n __typename\n ... on User {\n emailAddresses\n }\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "fbd6702b1d66c9949d49205fa661c44f"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery$variables, + RelayReaderRelayErrorHandlingTestNoncompliantEmptyScalarFieldWithoutThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientEdgeClientObjectWithMissingDataQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientEdgeClientObjectWithMissingDataQuery.graphql.js index 9fc8f1701e5d6..edb918c5d70ff 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientEdgeClientObjectWithMissingDataQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientEdgeClientObjectWithMissingDataQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<3d82cc55c5731b52368414cff0a59cb4>> * @flow * @lightSyntaxTransform * @nogrep @@ -103,7 +103,11 @@ return { "name": "astrological_sign", "plural": false, "selections": [ - (v0/*: any*/) + { + "kind": "CatchField", + "field": (v0/*: any*/), + "to": "NULL" + } ], "storageKey": null } @@ -202,7 +206,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f58793dca8d722401223f2d241a24705"; + (node/*: any*/).hash = "10b9776fee65d766ecdf6dec167c69da"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientPluralEdgeClientObjectWithMissingDataQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientPluralEdgeClientObjectWithMissingDataQuery.graphql.js index cdf1f359f9466..b4826b61cec22 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientPluralEdgeClientObjectWithMissingDataQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderRelayErrorHandlingTestResolverClientPluralEdgeClientObjectWithMissingDataQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<9f99ce813649707c96a87f5ada94fd01>> * @flow * @lightSyntaxTransform * @nogrep @@ -93,7 +93,11 @@ return { "name": "all_astrological_signs", "plural": true, "selections": [ - (v0/*: any*/) + { + "kind": "CatchField", + "field": (v0/*: any*/), + "to": "NULL" + } ], "storageKey": null } @@ -171,7 +175,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "301d67aac4a492fec857e800bb8ce687"; + (node/*: any*/).hash = "643cec3823d195129218fe86f024fb41"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestActorChangeQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestActorChangeQuery.graphql.js index 00b43b35d3b47..be427446176aa 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestActorChangeQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestActorChangeQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<35ee3663996ad62dfe90561eef84920c>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ var node/*: ConcreteRequest*/ = { }; if (__DEV__) { - (node/*: any*/).hash = "773250516ecbc96c49a303ebd13fe989"; + (node/*: any*/).hash = "cc9c977360e5fb08288904484b1cc752"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestShouldNotConsiderDataMissingIfTheFragmentTypeDoesNotMatchTheDataActorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestShouldNotConsiderDataMissingIfTheFragmentTypeDoesNotMatchTheDataActorQuery.graphql.js index a149e56b7b6ba..c0ad450cfb828 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestShouldNotConsiderDataMissingIfTheFragmentTypeDoesNotMatchTheDataActorQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestShouldNotConsiderDataMissingIfTheFragmentTypeDoesNotMatchTheDataActorQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<84e48e1e61d861745a24b057b9d1b5ce>> + * @generated SignedSource<<9f3ee690ec2d2556c725757e6abf21be>> * @flow * @lightSyntaxTransform * @nogrep @@ -140,7 +140,7 @@ var node/*: ConcreteRequest*/ = { }; if (__DEV__) { - (node/*: any*/).hash = "de40442fc17a47c16c0809a3cdc9acf7"; + (node/*: any*/).hash = "f1d5b3be29b85d51aafb11465e94b2fa"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestStreamConnectionUserQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestStreamConnectionUserQuery.graphql.js index c0fbacdd29033..54207aabffbc8 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestStreamConnectionUserQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReaderTestStreamConnectionUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<7d744f11f5417a944e40cb2005515511>> * @flow * @lightSyntaxTransform * @nogrep @@ -233,7 +233,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "49574b98d8f989c7596cd7bf981f5a7e"; + (node/*: any*/).hash = "6fea4f22e3efe059099ef5cfa350fc9c"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest1Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest1Query.graphql.js index a751545a8fbfb..d7e5f24ff58d4 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest1Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<560e11fb1bcfe70ea2dc5a656d17514e>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -270,7 +270,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "c93bd2646732b404b960bb12692d825a"; + (node/*: any*/).hash = "4aafabe534bb518cb3c2f17ba46c0a5b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest4Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest4Query.graphql.js index 4401eb7d64cb8..6fe19267b1d0a 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest4Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest4Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6329211e2fa9fffb6347d49ec17a98fb>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -251,7 +251,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "c0a1e569d98cf3c0c2b4a559325ed687"; + (node/*: any*/).hash = "3a3b10327f7853be9a3e2b6bf0a76a7d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest5Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest5Query.graphql.js index fafddc097def5..3b1062777f876 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest5Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest5Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6aeb66a6feca27660bbb6bce58a88f58>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -176,7 +176,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "0788b1f4742c878888dfe9389e4d9de4"; + (node/*: any*/).hash = "7b4c00aa61d93ed96cf7e372fcaf9a6d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest6Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest6Query.graphql.js index 22cda40059d88..bdddf055af89e 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest6Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<97f6e0668378af5c991ff2bf56fd9504>> + * @generated SignedSource<<66589315ffaeb5dae7119d5549099af0>> * @flow * @lightSyntaxTransform * @nogrep @@ -170,7 +170,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f6c61057e6890addba331b5b9df9fbb6"; + (node/*: any*/).hash = "c11d69bf3fe2868cfc206f53c56cbc72"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest7Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest7Query.graphql.js index c2c316acaf2f4..7a439338d3b6b 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest7Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest7Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<09693c211de3d81762b00236529c01b4>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -162,7 +162,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "e9f37482cdecc3ffcf60ff0a5957ffab"; + (node/*: any*/).hash = "19bfe0e6b96ae4a7feb5a3270cdd2153"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest8Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest8Query.graphql.js index 9d00bce836a8e..d1ffe6c397863 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest8Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayReferenceMarkerTest8Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<549f8082c61c89821da3f96db64fe1f5>> + * @generated SignedSource<<6f4ca7565504d82900ed85b322ecac08>> * @flow * @lightSyntaxTransform * @nogrep @@ -156,7 +156,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "30e3b31096520d2b76871a970230f544"; + (node/*: any*/).hash = "a0e01b7c5010f85f17c18767d704425a"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest10Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest10Query.graphql.js index 56698c9f1be69..d072b0742214d 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest10Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest10Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<4e400210e107bc7880b9b3b576cbb140>> + * @generated SignedSource<<0261c5ad4124d3fb09a73393b12b2219>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "25cdf6541b8272d4a77a346d81a442eb"; + (node/*: any*/).hash = "317e0d4a0d4e1c2fdceea8578eae916f"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest11Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest11Query.graphql.js index 988615ad85a1a..376910cddd55c 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest11Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest11Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<52e593a20fd57ecb4271b570ed043c01>> + * @generated SignedSource<<5e6d5c92de75ebab71a0880be83345ca>> * @flow * @lightSyntaxTransform * @nogrep @@ -166,7 +166,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "49b6f26955af4b56db48dc9bb544abdf"; + (node/*: any*/).hash = "4c5a0863a3eb64b65d62c3e333d69a06"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest12Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest12Query.graphql.js index 56b6f9999a074..31cca2748250f 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest12Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest12Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<4e8b698509bf6cbc4fdb043ee5b73a93>> * @flow * @lightSyntaxTransform * @nogrep @@ -166,7 +166,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "e2566f3cbdd63fc7ea2c74c81703d8e8"; + (node/*: any*/).hash = "086b7fb8e257be2c1e7e5baa629f7f3b"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest13Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest13Query.graphql.js index 231022e027651..28b34b4ac7aa7 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest13Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest13Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -178,7 +178,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "d9638dd9dcaa4dd9c95795b109acd65c"; + (node/*: any*/).hash = "b1fa2fdbc204811f15d320177b37e116"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest14Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest14Query.graphql.js index 8cbb4868ae0d4..12e65a0354215 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest14Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest14Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<8024bd1cfdbdf62c7064a0614c5e605b>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -156,7 +156,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "c173a8d4e918b5aaecb1da24d9f8f854"; + (node/*: any*/).hash = "16e672d11491bc0974f701a971e9bd97"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest41Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest41Query.graphql.js new file mode 100644 index 0000000000000..2b4e7504a417e --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest41Query.graphql.js @@ -0,0 +1,127 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayResponseNormalizerTest41Query$variables = {| + id: string, +|}; +export type RelayResponseNormalizerTest41Query$data = {| + +node: ?{| + +__typename: string, + +emailAddresses?: ?$ReadOnlyArray, + +id: string, + |}, +|}; +export type RelayResponseNormalizerTest41Query = {| + response: RelayResponseNormalizerTest41Query$data, + variables: RelayResponseNormalizerTest41Query$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } + ], + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "emailAddresses", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "RelayResponseNormalizerTest41Query", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "RelayResponseNormalizerTest41Query", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "f46c4a92011b2ed6e4222a610f749577", + "id": null, + "metadata": {}, + "name": "RelayResponseNormalizerTest41Query", + "operationKind": "query", + "text": "query RelayResponseNormalizerTest41Query(\n $id: ID!\n) {\n node(id: $id) {\n id\n __typename\n ... on User {\n emailAddresses\n }\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "3bf9e0ffd23df3d6711a66bca7879ca7"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayResponseNormalizerTest41Query$variables, + RelayResponseNormalizerTest41Query$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest4Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest4Query.graphql.js index 0530cfbe1e8d3..5913ff02ea373 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest4Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest4Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<1fef67311a2b88600ec8009d0f4dbe33>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -176,7 +176,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "325e859306b977210ac702e455a74207"; + (node/*: any*/).hash = "89fbaf152e9bd6bab74a5baad7e66dd1"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest5Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest5Query.graphql.js index 8bef8c3f6d46f..269cf1ed55bc0 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest5Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest5Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<4bedebbbabf24313bb3b68bc30c72a16>> * @flow * @lightSyntaxTransform * @nogrep @@ -170,7 +170,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "80a957b7f697c6ec8835d41f8e5cfecd"; + (node/*: any*/).hash = "de5b8815affe3b2ecc363ecebd2f06f1"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest6Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest6Query.graphql.js index 167b06a432550..0d07f3b2de17b 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest6Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -158,7 +158,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "6d72ae05b718f7c9fee011a92865e4b5"; + (node/*: any*/).hash = "391601564014900fbc9cceac74ffdcda"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest7Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest7Query.graphql.js index 589654dce888c..29c75d8a9de21 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest7Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest7Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<88a3db989d98394c766a0827b01066c5>> + * @generated SignedSource<<7c25b9b49e57d42c452f91038da43589>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "1b55aa70053112dca44375471deb0e3d"; + (node/*: any*/).hash = "1136d0edd20f9ef4cb63a1d100b394d9"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest8Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest8Query.graphql.js index 81605924a947e..e3a89265745ca 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest8Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest8Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -158,7 +158,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "636c5d32b4dd2e8695c5f9e9db86fa08"; + (node/*: any*/).hash = "38ba556a089ea79dcb91395dc95db966"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest9Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest9Query.graphql.js index 73489b2dcd9cc..70a5dcf2217dd 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest9Query.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest9Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<1c36a7296c1a1d33e3ad450d0f699c8b>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -188,7 +188,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "f2dffeabae2388e74241a6adde2168d4"; + (node/*: any*/).hash = "8c92153864fe205ace6fefbd5c53fdc4"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeQuery.graphql.js index 1bee0bb1a0864..6c7d96aa2c518 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<74ff7d309bac0d5896b6ddb964b4fdca>> + * @generated SignedSource<<4eb7f6555f0bdefabc5f3320e520fb5b>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ var node/*: ConcreteRequest*/ = { }; if (__DEV__) { - (node/*: any*/).hash = "0cca5a4e676a8ee5984e81c0ceda21ef"; + (node/*: any*/).hash = "35c07e751da3f8a045a2c9f9b099edde"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeWithAliasQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeWithAliasQuery.graphql.js index 2a5e073ef90f7..ae200f4f6b548 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeWithAliasQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestActorChangeWithAliasQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9b69ef76e0822508b19814660f2210d4>> + * @generated SignedSource<<5bef053c1adfdb1ffa0313258be7e692>> * @flow * @lightSyntaxTransform * @nogrep @@ -181,7 +181,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "4d26736797149779b0919c716b985847"; + (node/*: any*/).hash = "8ae75ed6d55511537f85750f1ff71def"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestError1Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestError1Query.graphql.js new file mode 100644 index 0000000000000..1ddacce3d8558 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestError1Query.graphql.js @@ -0,0 +1,97 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayResponseNormalizerTestError1Query$variables = {||}; +export type RelayResponseNormalizerTestError1Query$data = {| + +me: ?{| + +__typename: "User", + +id: string, + |}, +|}; +export type RelayResponseNormalizerTestError1Query = {| + response: RelayResponseNormalizerTestError1Query$data, + variables: RelayResponseNormalizerTestError1Query$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "RelayResponseNormalizerTestError1Query", + "selections": (v0/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayResponseNormalizerTestError1Query", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "96f38b7ac74f9f89da3f24a6a351d3b6", + "id": null, + "metadata": {}, + "name": "RelayResponseNormalizerTestError1Query", + "operationKind": "query", + "text": "query RelayResponseNormalizerTestError1Query {\n me {\n id\n __typename\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "8d91123fc080aa66577e44ce8b25b36c"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayResponseNormalizerTestError1Query$variables, + RelayResponseNormalizerTestError1Query$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestError2Query.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestError2Query.graphql.js new file mode 100644 index 0000000000000..40e265852007a --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestError2Query.graphql.js @@ -0,0 +1,97 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<1b546d5a26fba77d4458052b0e7ff488>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +export type RelayResponseNormalizerTestError2Query$variables = {||}; +export type RelayResponseNormalizerTestError2Query$data = {| + +me: ?{| + +id: string, + +lastName: ?string, + |}, +|}; +export type RelayResponseNormalizerTestError2Query = {| + response: RelayResponseNormalizerTestError2Query$data, + variables: RelayResponseNormalizerTestError2Query$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "lastName", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "RelayResponseNormalizerTestError2Query", + "selections": (v0/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "RelayResponseNormalizerTestError2Query", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "f2f151cc618234e9805058dab6dbef6b", + "id": null, + "metadata": {}, + "name": "RelayResponseNormalizerTestError2Query", + "operationKind": "query", + "text": "query RelayResponseNormalizerTestError2Query {\n me {\n id\n lastName\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "095f7e4f402153eeaefed504f57741be"; +} + +module.exports = ((node/*: any*/)/*: Query< + RelayResponseNormalizerTestError2Query$variables, + RelayResponseNormalizerTestError2Query$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestQuery.graphql.js index a8c2f71433ba8..66fce1d9bc16e 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTestQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9403bf41a2f46b24c1b361b32f5a865d>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -156,7 +156,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a4ef71f79408fa39d099bcbaa28d35e4"; + (node/*: any*/).hash = "596bef72849e29e5582e4bd84aae6f33"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest_pvQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest_pvQuery.graphql.js index 64cb9cd64628e..aad5bcde34f80 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest_pvQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/RelayResponseNormalizerTest_pvQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<337f3cce41670d8c20298d90ac0489fb>> * @flow * @lightSyntaxTransform * @nogrep @@ -213,7 +213,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "9177ab3c4ded4d7e93ff9712ce8a59c0"; + (node/*: any*/).hash = "3d11c5d77a6b30dd28ee9a5eb421373d"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestListUpdateFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestListUpdateFragment.graphql.js new file mode 100644 index 0000000000000..dd62e819b9696 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestListUpdateFragment.graphql.js @@ -0,0 +1,61 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestListUpdateFragment$fragmentType: FragmentType; +export type observeFragmentTestListUpdateFragment$data = $ReadOnlyArray<{| + +name: ?string, + +$fragmentType: observeFragmentTestListUpdateFragment$fragmentType, +|}>; +export type observeFragmentTestListUpdateFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestListUpdateFragment$data, + +$fragmentSpreads: observeFragmentTestListUpdateFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "observeFragmentTestListUpdateFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "30d272ba4e5c5a9eb1d9a79015a69ec3"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestListUpdateFragment$fragmentType, + observeFragmentTestListUpdateFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestListUpdateQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestListUpdateQuery.graphql.js new file mode 100644 index 0000000000000..70cac22b20f6e --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestListUpdateQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<4337e2999734809a390206fb499f653e>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestListUpdateFragment$fragmentType } from "./observeFragmentTestListUpdateFragment.graphql"; +export type observeFragmentTestListUpdateQuery$variables = {||}; +export type observeFragmentTestListUpdateQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestListUpdateQuery = {| + response: observeFragmentTestListUpdateQuery$data, + variables: observeFragmentTestListUpdateQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestListUpdateQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestListUpdateFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestListUpdateQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "17a222c7e13bc4a3b9c0c108377514da", + "id": null, + "metadata": {}, + "name": "observeFragmentTestListUpdateQuery", + "operationKind": "query", + "text": "query observeFragmentTestListUpdateQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...observeFragmentTestListUpdateFragment\n id\n }\n}\n\nfragment observeFragmentTestListUpdateFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "493ccdbc127bfccc347fc16107f21b79"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestListUpdateQuery$variables, + observeFragmentTestListUpdateQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralFragment.graphql.js new file mode 100644 index 0000000000000..ba317d7cf63f9 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralFragment.graphql.js @@ -0,0 +1,65 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<80e54ca26f89d2d71c3bb618efa15d49>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestMissingRequiredPluralFragment$fragmentType: FragmentType; +export type observeFragmentTestMissingRequiredPluralFragment$data = $ReadOnlyArray<{| + +name: string, + +$fragmentType: observeFragmentTestMissingRequiredPluralFragment$fragmentType, +|}>; +export type observeFragmentTestMissingRequiredPluralFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestMissingRequiredPluralFragment$data, + +$fragmentSpreads: observeFragmentTestMissingRequiredPluralFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "observeFragmentTestMissingRequiredPluralFragment", + "selections": [ + { + "kind": "RequiredField", + "field": { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + "action": "THROW" + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "0a62ca17583bf06a225f706e103dc11e"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestMissingRequiredPluralFragment$fragmentType, + observeFragmentTestMissingRequiredPluralFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralQuery.graphql.js new file mode 100644 index 0000000000000..d14055391be61 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<0ee8f9cd4d1a4269af40172b0c55884d>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestMissingRequiredPluralFragment$fragmentType } from "./observeFragmentTestMissingRequiredPluralFragment.graphql"; +export type observeFragmentTestMissingRequiredPluralQuery$variables = {||}; +export type observeFragmentTestMissingRequiredPluralQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestMissingRequiredPluralQuery = {| + response: observeFragmentTestMissingRequiredPluralQuery$data, + variables: observeFragmentTestMissingRequiredPluralQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestMissingRequiredPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestMissingRequiredPluralFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestMissingRequiredPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "d1213ecc01790c61de1e12d97a40c349", + "id": null, + "metadata": {}, + "name": "observeFragmentTestMissingRequiredPluralQuery", + "operationKind": "query", + "text": "query observeFragmentTestMissingRequiredPluralQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...observeFragmentTestMissingRequiredPluralFragment\n id\n }\n}\n\nfragment observeFragmentTestMissingRequiredPluralFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "1eb9c5256c37c4d0e28695bb4dd64fa8"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestMissingRequiredPluralQuery$variables, + observeFragmentTestMissingRequiredPluralQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestNetworkErrorFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestNetworkErrorFragment.graphql.js new file mode 100644 index 0000000000000..827cf692163a4 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestNetworkErrorFragment.graphql.js @@ -0,0 +1,72 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<63c81af48f685c620838abbe0a6ff26e>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestNetworkErrorFragment$fragmentType: FragmentType; +export type observeFragmentTestNetworkErrorFragment$data = {| + +me: ?{| + +name: ?string, + |}, + +$fragmentType: observeFragmentTestNetworkErrorFragment$fragmentType, +|}; +export type observeFragmentTestNetworkErrorFragment$key = { + +$data?: observeFragmentTestNetworkErrorFragment$data, + +$fragmentSpreads: observeFragmentTestNetworkErrorFragment$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestNetworkErrorFragment", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "08727ee370f3e8859731dc1535a5c718"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestNetworkErrorFragment$fragmentType, + observeFragmentTestNetworkErrorFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestNetworkErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestNetworkErrorQuery.graphql.js new file mode 100644 index 0000000000000..d48d6132b41c6 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestNetworkErrorQuery.graphql.js @@ -0,0 +1,98 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestNetworkErrorFragment$fragmentType } from "./observeFragmentTestNetworkErrorFragment.graphql"; +export type observeFragmentTestNetworkErrorQuery$variables = {||}; +export type observeFragmentTestNetworkErrorQuery$data = {| + +$fragmentSpreads: observeFragmentTestNetworkErrorFragment$fragmentType, +|}; +export type observeFragmentTestNetworkErrorQuery = {| + response: observeFragmentTestNetworkErrorQuery$data, + variables: observeFragmentTestNetworkErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestNetworkErrorQuery", + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestNetworkErrorFragment" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestNetworkErrorQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "ea59f42835e1af47e66fc74d78ea34fb", + "id": null, + "metadata": {}, + "name": "observeFragmentTestNetworkErrorQuery", + "operationKind": "query", + "text": "query observeFragmentTestNetworkErrorQuery {\n ...observeFragmentTestNetworkErrorFragment\n}\n\nfragment observeFragmentTestNetworkErrorFragment on Query {\n me {\n name\n id\n }\n}\n" + } +}; + +if (__DEV__) { + (node/*: any*/).hash = "ab0f402fbc738d3f90847297471bd4b3"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestNetworkErrorQuery$variables, + observeFragmentTestNetworkErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralFragment.graphql.js new file mode 100644 index 0000000000000..f5d80766c2a15 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralFragment.graphql.js @@ -0,0 +1,61 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestPluralFragment$fragmentType: FragmentType; +export type observeFragmentTestPluralFragment$data = $ReadOnlyArray<{| + +name: ?string, + +$fragmentType: observeFragmentTestPluralFragment$fragmentType, +|}>; +export type observeFragmentTestPluralFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestPluralFragment$data, + +$fragmentSpreads: observeFragmentTestPluralFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "observeFragmentTestPluralFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "3b473578ee9b2f35ed7214e714f68334"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestPluralFragment$fragmentType, + observeFragmentTestPluralFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralQuery.graphql.js new file mode 100644 index 0000000000000..d6ed1fc180fc6 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<8ed3e238203c49288429f434ff0ef253>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestPluralFragment$fragmentType } from "./observeFragmentTestPluralFragment.graphql"; +export type observeFragmentTestPluralQuery$variables = {||}; +export type observeFragmentTestPluralQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestPluralQuery = {| + response: observeFragmentTestPluralQuery$data, + variables: observeFragmentTestPluralQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestPluralFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "ccff1412490c5e62d70031d41db0c7e4", + "id": null, + "metadata": {}, + "name": "observeFragmentTestPluralQuery", + "operationKind": "query", + "text": "query observeFragmentTestPluralQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...observeFragmentTestPluralFragment\n id\n }\n}\n\nfragment observeFragmentTestPluralFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "c1a2f68df2ec25bc00b077d6cdecdce4"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestPluralQuery$variables, + observeFragmentTestPluralQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorFragment.graphql.js new file mode 100644 index 0000000000000..122853d5c2de7 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorFragment.graphql.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<73dfa993cd14eb071971ec8ae446eea0>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType: FragmentType; +export type observeFragmentTestPluralThrowOnFieldErrorFragment$data = $ReadOnlyArray<{| + +name: ?string, + +$fragmentType: observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType, +|}>; +export type observeFragmentTestPluralThrowOnFieldErrorFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestPluralThrowOnFieldErrorFragment$data, + +$fragmentSpreads: observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "throwOnFieldError": true + }, + "name": "observeFragmentTestPluralThrowOnFieldErrorFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "531291e1335ff8e4ffacf60c7a6064ed"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType, + observeFragmentTestPluralThrowOnFieldErrorFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..a7a23d3f32ffe --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType } from "./observeFragmentTestPluralThrowOnFieldErrorFragment.graphql"; +export type observeFragmentTestPluralThrowOnFieldErrorQuery$variables = {||}; +export type observeFragmentTestPluralThrowOnFieldErrorQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestPluralThrowOnFieldErrorQuery = {| + response: observeFragmentTestPluralThrowOnFieldErrorQuery$data, + variables: observeFragmentTestPluralThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestPluralThrowOnFieldErrorFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "1e83abfe97b66be09a6642b3332e4d09", + "id": null, + "metadata": {}, + "name": "observeFragmentTestPluralThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query observeFragmentTestPluralThrowOnFieldErrorQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...observeFragmentTestPluralThrowOnFieldErrorFragment\n id\n }\n}\n\nfragment observeFragmentTestPluralThrowOnFieldErrorFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "36cd146fd2db4ac80dfe226a3e20dd3e"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestPluralThrowOnFieldErrorQuery$variables, + observeFragmentTestPluralThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql.js new file mode 100644 index 0000000000000..3bd37816c2c5f --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql.js @@ -0,0 +1,78 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { UserAlwaysThrowsResolver$key } from "./../resolvers/__generated__/UserAlwaysThrowsResolver.graphql"; +import type { FragmentType } from "relay-runtime"; +import {always_throws as userAlwaysThrowsResolverType} from "../resolvers/UserAlwaysThrowsResolver.js"; +import type { TestResolverContextType } from "../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `userAlwaysThrowsResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userAlwaysThrowsResolverType: ( + rootKey: UserAlwaysThrowsResolver$key, + args: void, + context: TestResolverContextType, +) => ?string); +declare export opaque type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType: FragmentType; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$data = $ReadOnlyArray<{| + +always_throws: ?string, + +$fragmentType: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType, +|}>; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$data, + +$fragmentSpreads: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "throwOnFieldError": true + }, + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment", + "selections": [ + { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "UserAlwaysThrowsResolver" + }, + "kind": "RelayResolver", + "name": "always_throws", + "resolverModule": require('./../resolvers/UserAlwaysThrowsResolver').always_throws, + "path": "always_throws" + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "59a6f5ddf61e54affd5726b8cf322183"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType, + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..924a7c4f2ce5a --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,146 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<88f631a8a727158afc72c5ed15b804a4>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType } from "./observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql"; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$variables = {||}; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery = {| + response: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$data, + variables: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "7", + "8" + ] + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment" + } + ], + "storageKey": "nodes(ids:[\"7\",\"8\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + (v1/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + { + "name": "always_throws", + "args": null, + "fragment": { + "kind": "InlineFragment", + "selections": [ + (v1/*: any*/) + ], + "type": "User", + "abstractKey": null + }, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": "nodes(ids:[\"7\",\"8\"])" + } + ] + }, + "params": { + "cacheID": "cda0054b75d8a0bc0abaacbb14186b4a", + "id": null, + "metadata": {}, + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery {\n nodes(ids: [\"7\", \"8\"]) {\n __typename\n ...observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment\n id\n }\n}\n\nfragment UserAlwaysThrowsResolver on User {\n __typename\n}\n\nfragment observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment on User {\n ...UserAlwaysThrowsResolver\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "412492582875c8c7b44e67794ed55763"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$variables, + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/readInlineDataTestUserQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/readInlineDataTestUserQuery.graphql.js index 88fc2474f71a5..b47f26d73cfed 100644 --- a/packages/relay-runtime/store/__tests__/__generated__/readInlineDataTestUserQuery.graphql.js +++ b/packages/relay-runtime/store/__tests__/__generated__/readInlineDataTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<10034eb057a199176c4362dd541b97c3>> + * @generated SignedSource<<6a37ab03e5df65024c27b4da8cfd151d>> * @flow * @lightSyntaxTransform * @nogrep @@ -148,7 +148,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "64aaa0bdd963532aa7d5e61221722bca"; + (node/*: any*/).hash = "27f84c47b8d1f1f6f15e5a5869ff2687"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/store/__tests__/__generated__/waitForFragmentDataTestOkPluralFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/waitForFragmentDataTestOkPluralFragment.graphql.js new file mode 100644 index 0000000000000..ecd0f3164f631 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/waitForFragmentDataTestOkPluralFragment.graphql.js @@ -0,0 +1,61 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<2ed8051023394e48547a26c640b8e13c>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type waitForFragmentDataTestOkPluralFragment$fragmentType: FragmentType; +export type waitForFragmentDataTestOkPluralFragment$data = $ReadOnlyArray<{| + +name: ?string, + +$fragmentType: waitForFragmentDataTestOkPluralFragment$fragmentType, +|}>; +export type waitForFragmentDataTestOkPluralFragment$key = $ReadOnlyArray<{ + +$data?: waitForFragmentDataTestOkPluralFragment$data, + +$fragmentSpreads: waitForFragmentDataTestOkPluralFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "waitForFragmentDataTestOkPluralFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "27b1b1a834949ad358eaf6d1396d3f9d"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + waitForFragmentDataTestOkPluralFragment$fragmentType, + waitForFragmentDataTestOkPluralFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/waitForFragmentDataTestOkPluralQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/waitForFragmentDataTestOkPluralQuery.graphql.js new file mode 100644 index 0000000000000..c1f1dc35eef47 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/waitForFragmentDataTestOkPluralQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<5eca2a10e99142f6f4e5d99b02421ad1>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { waitForFragmentDataTestOkPluralFragment$fragmentType } from "./waitForFragmentDataTestOkPluralFragment.graphql"; +export type waitForFragmentDataTestOkPluralQuery$variables = {||}; +export type waitForFragmentDataTestOkPluralQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type waitForFragmentDataTestOkPluralQuery = {| + response: waitForFragmentDataTestOkPluralQuery$data, + variables: waitForFragmentDataTestOkPluralQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "waitForFragmentDataTestOkPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "waitForFragmentDataTestOkPluralFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "waitForFragmentDataTestOkPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "91c66e0b45b06f9cc7a66477f8156418", + "id": null, + "metadata": {}, + "name": "waitForFragmentDataTestOkPluralQuery", + "operationKind": "query", + "text": "query waitForFragmentDataTestOkPluralQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...waitForFragmentDataTestOkPluralFragment\n id\n }\n}\n\nfragment waitForFragmentDataTestOkPluralFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "139b32cebe816906461147bcb6b1db45"; +} + +module.exports = ((node/*: any*/)/*: Query< + waitForFragmentDataTestOkPluralQuery$variables, + waitForFragmentDataTestOkPluralQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/observeFragment-test.js b/packages/relay-runtime/store/__tests__/observeFragment-test.js index 484a74009c32c..0bbfe7084a23a 100644 --- a/packages/relay-runtime/store/__tests__/observeFragment-test.js +++ b/packages/relay-runtime/store/__tests__/observeFragment-test.js @@ -145,6 +145,35 @@ test('Missing required data', async () => { }); }); +test('Keep loading on network error', async () => { + const query = graphql` + query observeFragmentTestNetworkErrorQuery { + ...observeFragmentTestNetworkErrorFragment + } + `; + + const fragment = graphql` + fragment observeFragmentTestNetworkErrorFragment on Query { + me { + name + } + } + `; + + const environment = createMockEnvironment(); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + fetchQuery(environment, query, variables).subscribe({}); + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data); + withObservableValues(observable, results => { + expect(results).toEqual([{state: 'loading'}]); + environment.mock.reject(operation, new Error('Network error')); + expect(results).toEqual([{state: 'loading'}]); + }); +}); + test('Field error with @throwOnFieldError', async () => { const query = graphql` query observeFragmentTestThrowOnFieldErrorQuery { @@ -230,7 +259,7 @@ test('Resolver error with @throwOnFieldError', async () => { expect(results).toEqual([ { error: new Error( - "Relay: Resolver error at path 'always_throws' in 'observeFragmentTestResolverErrorWithThrowOnFieldErrorFragment'.", + "Relay: Resolver error at path 'always_throws' in 'observeFragmentTestResolverErrorWithThrowOnFieldErrorFragment'. Message: I always throw. What did you expect?", ), state: 'error', }, @@ -337,6 +366,238 @@ test('read deferred fragment', async () => { }); }); +test('observes a plural fragment', async () => { + const query = graphql` + query observeFragmentTestPluralQuery { + nodes(ids: ["1", "2"]) { + ...observeFragmentTestPluralFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestPluralFragment on User @relay(plural: true) { + name + } + `; + + const environment = createMockEnvironment({ + store: new LiveResolverStore(new RelayRecordSource()), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + {id: '1', __typename: 'User', name: 'Alice'}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }); + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + const result = await observable.toPromise(); + expect(result).toEqual({ + state: 'ok', + value: [{name: 'Alice'}, {name: 'Bob'}], + }); +}); + +test('Missing required data on plural fragment', async () => { + const query = graphql` + query observeFragmentTestMissingRequiredPluralQuery { + nodes(ids: ["1", "2"]) { + ...observeFragmentTestMissingRequiredPluralFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestMissingRequiredPluralFragment on User + @relay(plural: true) { + name @required(action: THROW) + } + `; + + const environment = createMockEnvironment(); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + // Name is null despite being required + {id: '1', __typename: 'User', name: null}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }); + + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + withObservableValues(observable, results => { + expect(results).toEqual([ + { + error: new Error( + "Relay: Missing @required value at path 'name' in 'observeFragmentTestMissingRequiredPluralFragment'.", + ), + state: 'error', + }, + ]); + }); +}); + +test('Field error with @relay(plural: true) @throwOnFieldError', async () => { + const query = graphql` + query observeFragmentTestPluralThrowOnFieldErrorQuery { + nodes(ids: ["1", "2"]) { + ...observeFragmentTestPluralThrowOnFieldErrorFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestPluralThrowOnFieldErrorFragment on User + @relay(plural: true) + @throwOnFieldError { + name + } + `; + + let dataSource: Sink; + const fetch = ( + _query: RequestParameters, + _variables: Variables, + _cacheConfig: CacheConfig, + ) => { + // $FlowFixMe[missing-local-annot] Error found while enabling LTI on this file + return RelayObservable.create(sink => { + dataSource = sink; + }); + }; + + const environment = createMockEnvironment({ + network: RelayNetwork.create(fetch), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + + environment.execute({operation}).subscribe({}); + invariant(dataSource != null, 'Expected data source to be set'); + dataSource.next({ + data: { + nodes: [ + {id: '1', __typename: 'User', name: null}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }, + errors: [{message: 'error', path: ['nodes', 0, 'name']}], + }); + + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + withObservableValues(observable, results => { + expect(results).toEqual([ + { + error: new Error( + 'Relay: Unexpected response payload - check server logs for details.', + ), + state: 'error', + }, + ]); + }); +}); + +test('Resolver error with @relay(plural: true) @throwOnFieldError', async () => { + const query = graphql` + query observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery { + nodes(ids: ["7", "8"]) { + ...observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment on User + @relay(plural: true) + @throwOnFieldError { + always_throws + } + `; + + const environment = createMockEnvironment({ + store: new LiveResolverStore(new RelayRecordSource()), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + {id: '7', __typename: 'User'}, + {id: '8', __typename: 'User'}, + ], + }); + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + withObservableValues(observable, results => { + expect(results).toEqual([ + { + error: new Error( + "Relay: Resolver error at path 'always_throws' in 'observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment'. Message: I always throw. What did you expect?", + ), + state: 'error', + }, + ]); + }); +}); + +test('Store update across list items notifies multiple times', async () => { + const query = graphql` + query observeFragmentTestListUpdateQuery { + nodes(ids: ["1", "2"]) { + ...observeFragmentTestListUpdateFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestListUpdateFragment on User + @relay(plural: true) { + name + } + `; + + const environment = createMockEnvironment({ + store: new LiveResolverStore(new RelayRecordSource()), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + {id: '1', __typename: 'User', name: 'Alice'}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }); + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + withObservableValues(observable, results => { + expect(results).toEqual([ + {state: 'ok', value: [{name: 'Alice'}, {name: 'Bob'}]}, + ]); + + environment.commitPayload(operation, { + nodes: [ + {id: '1', __typename: 'User', name: 'Alice updated'}, + {id: '2', __typename: 'User', name: 'Bob updated'}, + ], + }); + expect(results).toEqual([ + {state: 'ok', value: [{name: 'Alice'}, {name: 'Bob'}]}, + {state: 'ok', value: [{name: 'Alice updated'}, {name: 'Bob'}]}, + {state: 'ok', value: [{name: 'Alice updated'}, {name: 'Bob updated'}]}, + ]); + }); +}); + test('data goes missing due to unrelated query response', async () => { const query = graphql` query observeFragmentTestMissingDataQuery { diff --git a/packages/relay-runtime/store/__tests__/readInlineData-test.js b/packages/relay-runtime/store/__tests__/readInlineData-test.js index f331e736420b5..40339bb3cc08b 100644 --- a/packages/relay-runtime/store/__tests__/readInlineData-test.js +++ b/packages/relay-runtime/store/__tests__/readInlineData-test.js @@ -28,7 +28,7 @@ disallowWarnings(); const UserQuery = graphql` query readInlineDataTestUserQuery($id: ID!) { node(id: $id) { - ...readInlineDataTestUserFragment # @arguments(cond: true) + ...readInlineDataTestUserFragment @dangerously_unaliased_fixme # @arguments(cond: true) } # with_name: node(id: $id) { # id diff --git a/packages/relay-runtime/store/__tests__/relayReaderTestExecTimeResolversFalseProvider.js b/packages/relay-runtime/store/__tests__/relayReaderTestExecTimeResolversFalseProvider.js new file mode 100644 index 0000000000000..9cd2d666e3a28 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/relayReaderTestExecTimeResolversFalseProvider.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall relay + */ + +'use strict'; + +module.exports = { + get(): boolean { + return false; + }, +}; diff --git a/packages/relay-runtime/store/__tests__/relayReaderTestExecTimeResolversTrueProvider.js b/packages/relay-runtime/store/__tests__/relayReaderTestExecTimeResolversTrueProvider.js new file mode 100644 index 0000000000000..ae80b363d857a --- /dev/null +++ b/packages/relay-runtime/store/__tests__/relayReaderTestExecTimeResolversTrueProvider.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall relay + */ + +'use strict'; + +module.exports = { + get(): boolean { + return true; + }, +}; diff --git a/packages/relay-runtime/store/__tests__/resolvers/AstrologicalSignUtils.js b/packages/relay-runtime/store/__tests__/resolvers/AstrologicalSignUtils.js index cc440a9e7e7af..0ba068ad7b22a 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/AstrologicalSignUtils.js +++ b/packages/relay-runtime/store/__tests__/resolvers/AstrologicalSignUtils.js @@ -68,7 +68,7 @@ const HOUSE_ORDER = [ function findSign(month: number, day: number): AstrologicalSignID { const days = [21, 20, 21, 21, 22, 22, 23, 24, 24, 24, 23, 22]; - const signs = [ + const signs: AstrologicalSignID[] = [ 'Aquarius', 'Pisces', 'Aries', diff --git a/packages/relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver.js b/packages/relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver.js index 4730b15d34408..820559df92615 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver.js +++ b/packages/relay-runtime/store/__tests__/resolvers/LiveCounterContextResolver.js @@ -44,6 +44,79 @@ function counter_context( }; } +/** + * @RelayResolver BaseCounter + * @weak + */ +export type BaseCounter = { + count: number, +}; + +/** + * @RelayResolver Query.base_counter_context: BaseCounter + * @live + * + * A Relay Resolver that returns an object implementing the External State + * Resolver interface. + */ +function base_counter_context( + _args: void, + context: TestResolverContextType, +): LiveState { + let value = 0; + + return { + read() { + return { + count: value, + }; + }, + subscribe(cb): () => void { + const subscription = context.counter.subscribe({ + next: v => { + value = v; + cb(); + }, + }); + + return () => subscription.unsubscribe(); + }, + }; +} + +/** + * @RelayResolver BaseCounter.count_plus_one: Int + * @live + * + * A Relay Resolver that returns an object implementing the External State + * Resolver interface. + */ +function count_plus_one( + _parent: mixed, + _args: void, + context: TestResolverContextType, +): LiveState { + let value = 0; + + return { + read() { + return value; + }, + subscribe(cb): () => void { + const subscription = context.counter.subscribe({ + next: v => { + value = v + 1; + cb(); + }, + }); + + return () => subscription.unsubscribe(); + }, + }; +} + module.exports = { counter_context, + base_counter_context, + count_plus_one, }; diff --git a/packages/relay-runtime/store/__tests__/resolvers/LiveResolvers-test.js b/packages/relay-runtime/store/__tests__/resolvers/LiveResolvers-test.js index 3c1c610efadaa..821fbf4f0d5b0 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/LiveResolvers-test.js +++ b/packages/relay-runtime/store/__tests__/resolvers/LiveResolvers-test.js @@ -256,7 +256,7 @@ test('Errors thrown during _initial_ read() are caught as resolver errors', () = }); const snapshot = environment.lookup(operation.fragment); - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { kind: 'relay_resolver.error', error: Error('What?'), @@ -299,7 +299,7 @@ test('Errors thrown during read() _after update_ are caught as resolver errors', environment.subscribe(snapshot, handler); // Confirm there are no initial errors - expect(snapshot.errorResponseFields).toEqual(null); + expect(snapshot.fieldErrors).toEqual(null); const data: $FlowExpectedError = snapshot.data; expect(data.counter_throws_when_odd).toBe(0); @@ -310,7 +310,7 @@ test('Errors thrown during read() _after update_ are caught as resolver errors', const nextSnapshot = handler.mock.calls[0][0]; - expect(nextSnapshot.errorResponseFields).toEqual([ + expect(nextSnapshot.fieldErrors).toEqual([ { kind: 'relay_resolver.error', error: Error('What?'), @@ -331,7 +331,7 @@ test('Errors thrown during read() _after update_ are caught as resolver errors', const finalSnapshot = handler.mock.calls[0][0]; // Confirm there are no initial errors - expect(finalSnapshot.errorResponseFields).toEqual(null); + expect(finalSnapshot.fieldErrors).toEqual(null); const finalData: $FlowExpectedError = finalSnapshot.data; expect(finalData.counter_throws_when_odd).toBe(2); }); diff --git a/packages/relay-runtime/store/__tests__/resolvers/Resolver-test.js b/packages/relay-runtime/store/__tests__/resolvers/Resolver-test.js index 93aa49b1af3b1..dbcf654400ce1 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/Resolver-test.js +++ b/packages/relay-runtime/store/__tests__/resolvers/Resolver-test.js @@ -125,8 +125,8 @@ describe('Relay Resolver', () => { environment.commitPayload(operation, {}); - const {data, errorResponseFields} = environment.lookup(operation.fragment); - expect(errorResponseFields).toBe(null); + const {data, fieldErrors} = environment.lookup(operation.fragment); + expect(fieldErrors).toBe(null); // $FlowFixMe[incompatible-use] Lookup is untyped expect(data.hello_optional_world).toEqual('Hello, Default!'); diff --git a/packages/relay-runtime/store/__tests__/resolvers/ResolverGC-test.js b/packages/relay-runtime/store/__tests__/resolvers/ResolverGC-test.js index d77946a896124..5ea579b266efb 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/ResolverGC-test.js +++ b/packages/relay-runtime/store/__tests__/resolvers/ResolverGC-test.js @@ -10,6 +10,7 @@ */ 'use strict'; + import type {GraphQLResponse} from '../../../network/RelayNetworkTypes'; import type {ConcreteRequest} from '../../../util/RelayConcreteNode'; import type { @@ -40,6 +41,9 @@ const { } = require('relay-runtime/store/RelayModernOperationDescriptor'); const RelayModernStore = require('relay-runtime/store/RelayModernStore.js'); const RelayRecordSource = require('relay-runtime/store/RelayRecordSource'); +const { + RELAY_READ_TIME_RESOLVER_KEY_PREFIX, +} = require('relay-runtime/store/RelayStoreUtils'); const { disallowConsoleErrors, disallowWarnings, @@ -70,7 +74,7 @@ test('Live Resolver without fragment', async () => { expect(snapshot.data).toEqual({counter_no_fragment: 0}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:counter_no_fragment', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_no_fragment`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { @@ -78,7 +82,7 @@ test('Live Resolver without fragment', async () => { expect(snapshot.data).toEqual({counter_no_fragment: 0}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:counter_no_fragment', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_no_fragment`, ]); }, afterFreedGC: recordIdsInStore => { @@ -89,7 +93,7 @@ test('Live Resolver without fragment', async () => { expect(snapshot.data).toEqual({counter_no_fragment: 0}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:counter_no_fragment', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_no_fragment`, ]); }, }); @@ -114,7 +118,7 @@ test('Live Resolver _with_ root fragment', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:counter', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { @@ -123,7 +127,7 @@ test('Live Resolver _with_ root fragment', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:counter', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, ]); }, afterFreedGC: recordIdsInStore => { @@ -133,7 +137,10 @@ test('Live Resolver _with_ root fragment', async () => { expect(counterResolver.callCount - initialCallCount).toBe(2); // Note that we _can't_ recreate the Resolver value because it's root fragment has been GGed. expect(snapshot.data).toEqual({counter: undefined}); - expect(recordIdsInStore).toEqual(['client:root', 'client:root:counter']); + expect(recordIdsInStore).toEqual([ + 'client:root', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, + ]); }, }); }); @@ -155,8 +162,8 @@ test('Regular resolver with fragment reads live resovler with fragment', async ( expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:counter', - 'client:root:counter_plus_one', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_plus_one`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { @@ -164,8 +171,8 @@ test('Regular resolver with fragment reads live resovler with fragment', async ( expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:counter', - 'client:root:counter_plus_one', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_plus_one`, ]); }, afterFreedGC: recordIdsInStore => { @@ -173,7 +180,7 @@ test('Regular resolver with fragment reads live resovler with fragment', async ( }, afterLookupAfterFreedGC: (snapshot, recordIdsInStore) => { expect(snapshot.data).toEqual({counter_plus_one: null}); - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { fieldPath: 'me.', kind: 'missing_expected_data.log', @@ -188,8 +195,8 @@ test('Regular resolver with fragment reads live resovler with fragment', async ( ]); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:counter', - 'client:root:counter_plus_one', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter`, + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}counter_plus_one`, ]); }, }); @@ -214,7 +221,7 @@ test('Non-live Resolver with fragment', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:greeting', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}greeting`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { @@ -222,7 +229,7 @@ test('Non-live Resolver with fragment', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:greeting', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}greeting`, ]); }, afterFreedGC: recordIdsInStore => { @@ -252,14 +259,14 @@ test('Non-live Resolver with no fragment and static arguments', async () => { expect(snapshot.data).toEqual({hello: 'Hello, Planet!'}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:hello(world:"Planet")', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}hello(world:"Planet")`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { expect(snapshot.data).toEqual({hello: 'Hello, Planet!'}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:hello(world:"Planet")', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}hello(world:"Planet")`, ]); }, afterFreedGC: recordIdsInStore => { @@ -269,7 +276,7 @@ test('Non-live Resolver with no fragment and static arguments', async () => { expect(snapshot.data).toEqual({hello: 'Hello, Planet!'}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:hello(world:"Planet")', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}hello(world:"Planet")`, ]); }, }); @@ -291,14 +298,14 @@ test('Non-live Resolver with no fragment and dynamic arguments', async () => { expect(snapshot.data).toEqual({hello: 'Hello, Planet!'}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:hello(world:"Planet")', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}hello(world:"Planet")`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { expect(snapshot.data).toEqual({hello: 'Hello, Planet!'}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:hello(world:"Planet")', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}hello(world:"Planet")`, ]); }, afterFreedGC: recordIdsInStore => { @@ -309,7 +316,7 @@ test('Non-live Resolver with no fragment and dynamic arguments', async () => { expect(snapshot.data).toEqual({hello: 'Hello, Planet!'}); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:hello(world:"Planet")', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}hello(world:"Planet")`, ]); }, }); @@ -366,7 +373,7 @@ test('Resolver reading a client-edge to a server type', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, '1337', '1234', ]); @@ -385,7 +392,7 @@ test('Resolver reading a client-edge to a server type', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, '1337', '1234', ]); @@ -457,9 +464,9 @@ test('Resolver reading a client-edge to a server type (recursive)', async () => expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, '1337', - 'client:1337:another_client_edge', + `client:1337:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}another_client_edge`, '1338', ]); }, @@ -477,9 +484,9 @@ test('Resolver reading a client-edge to a server type (recursive)', async () => expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:client_edge', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}client_edge`, '1337', - 'client:1337:another_client_edge', + `client:1337:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}another_client_edge`, '1338', ]); }, @@ -527,11 +534,11 @@ test('Resolver reading a client-edge to a client type', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:birthdate', - 'client:1:astrological_sign', - 'client:AstrologicalSign:Pisces', - 'client:AstrologicalSign:Pisces:self', - 'client:AstrologicalSign:Pisces:name', + `client:1:birthdate`, + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}astrological_sign`, + `client:AstrologicalSign:Pisces`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { @@ -542,10 +549,10 @@ test('Resolver reading a client-edge to a client type', async () => { 'client:root', '1', 'client:1:birthdate', - 'client:1:astrological_sign', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}astrological_sign`, 'client:AstrologicalSign:Pisces', - 'client:AstrologicalSign:Pisces:self', - 'client:AstrologicalSign:Pisces:name', + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, ]); }, @@ -593,11 +600,11 @@ test('Resolver reading a client-edge to a client type (resolver marked dirty)', expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:birthdate', - 'client:1:astrological_sign', - 'client:AstrologicalSign:Pisces', - 'client:AstrologicalSign:Pisces:self', - 'client:AstrologicalSign:Pisces:name', + `client:1:birthdate`, + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}astrological_sign`, + `client:AstrologicalSign:Pisces`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, ]); /* Here we update the user to invalidate the astrological_sign resolver */ @@ -615,10 +622,10 @@ test('Resolver reading a client-edge to a client type (resolver marked dirty)', 'client:root', '1', 'client:1:birthdate', - 'client:1:astrological_sign', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}astrological_sign`, 'client:AstrologicalSign:Pisces', - 'client:AstrologicalSign:Pisces:self', - 'client:AstrologicalSign:Pisces:name', + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, ]); }, @@ -658,7 +665,7 @@ test('Resolver reading a client-edge to a client type (suspended)', async () => expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:virgo_suspends_when_counter_is_odd', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}virgo_suspends_when_counter_is_odd`, // We don't have any of the Virgo records because they were not created. ]); }, @@ -667,7 +674,7 @@ test('Resolver reading a client-edge to a client type (suspended)', async () => expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:virgo_suspends_when_counter_is_odd', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}virgo_suspends_when_counter_is_odd`, // We don't have any of the Virgo records because they were not created. ]); }, @@ -704,7 +711,7 @@ test('Resolver reading a plural client-edge to a client type', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:all_astrological_signs', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}all_astrological_signs`, ...HOUSE_ORDER.map(name => `client:AstrologicalSign:${name}`), ]); }, @@ -717,7 +724,7 @@ test('Resolver reading a plural client-edge to a client type', async () => { expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:root:all_astrological_signs', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}all_astrological_signs`, ...HOUSE_ORDER.map(name => `client:AstrologicalSign:${name}`), ]); }, @@ -728,7 +735,7 @@ test('Resolver reading a plural client-edge to a client type', async () => { afterLookupAfterFreedGC: (snapshot, recordIdsInStore) => { // Note that we _can't_ recreate the Resolver value because it's root fragment has been GGed. expect(snapshot.data).toEqual({all_astrological_signs: null}); - expect(snapshot.errorResponseFields).toEqual([ + expect(snapshot.fieldErrors).toEqual([ { fieldPath: 'me.', kind: 'missing_expected_data.log', @@ -737,7 +744,7 @@ test('Resolver reading a plural client-edge to a client type', async () => { ]); expect(recordIdsInStore).toEqual([ 'client:root', - 'client:root:all_astrological_signs', + `client:root:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}all_astrological_signs`, ]); }, }); @@ -779,15 +786,15 @@ test('Resolver reading a client-edge to a client type (recursive)', async () => expect(recordIdsInStore).toEqual([ 'client:root', '1', - 'client:1:birthdate', - 'client:1:astrological_sign', - 'client:AstrologicalSign:Pisces', - 'client:AstrologicalSign:Pisces:self', - 'client:AstrologicalSign:Pisces:name', - 'client:AstrologicalSign:Pisces:opposite', - 'client:AstrologicalSign:Virgo', - 'client:AstrologicalSign:Virgo:self', - 'client:AstrologicalSign:Virgo:name', + `client:1:birthdate`, + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}astrological_sign`, + `client:AstrologicalSign:Pisces`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}opposite`, + `client:AstrologicalSign:Virgo`, + `client:AstrologicalSign:Virgo:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Virgo:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, ]); }, afterRetainedGC: (snapshot, recordIdsInStore) => { @@ -799,14 +806,14 @@ test('Resolver reading a client-edge to a client type (recursive)', async () => 'client:root', '1', 'client:1:birthdate', - 'client:1:astrological_sign', + `client:1:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}astrological_sign`, 'client:AstrologicalSign:Pisces', - 'client:AstrologicalSign:Pisces:self', - 'client:AstrologicalSign:Pisces:name', - 'client:AstrologicalSign:Pisces:opposite', + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, + `client:AstrologicalSign:Pisces:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}opposite`, 'client:AstrologicalSign:Virgo', - 'client:AstrologicalSign:Virgo:self', - 'client:AstrologicalSign:Virgo:name', + `client:AstrologicalSign:Virgo:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}self`, + `client:AstrologicalSign:Virgo:${RELAY_READ_TIME_RESOLVER_KEY_PREFIX}name`, ]); }, afterFreedGC: recordIdsInStore => { @@ -820,6 +827,85 @@ test('Resolver reading a client-edge to a client type (recursive)', async () => }); }); +test.each([0, 1, 5])( + 'Live Resolver cleanup when %i references retained', + async numRetainedReferences => { + const unsubscribeMock = jest.fn(); + const subscribeSpy = jest + .spyOn(GLOBAL_STORE, 'subscribe') + .mockImplementation(() => { + return unsubscribeMock; + }); + + // Reset the store before each test run + resetStore(); + + const source = RelayRecordSource.create(); + + const store = new RelayModernStore(source, { + gcReleaseBufferSize: 0, + }); + + const environment = new RelayModernEnvironment({ + network: RelayNetwork.create((request, variables) => { + return Promise.resolve({data: {}}); + }), + store, + }); + + // The operation that uses the live resolver + const operation = createOperationDescriptor( + graphql` + query ResolverGCTestNoRetainedQueriesQuery { + counter_no_fragment + } + `, + {}, + ); + + // Execute the query to populate the store + await environment.execute({operation}).toPromise(); + + // Lookup the data to trigger evaluation of the resolver + const snapshot = environment.lookup(operation.fragment); + + // Ensure the live resolver has been called + expect(subscribeSpy).toHaveBeenCalledTimes(1); + expect(snapshot.data).toEqual({counter_no_fragment: 0}); + + // Retain the operation if numRetainedReferences > 0 + const retains = []; + for (let i = 0; i < numRetainedReferences; i++) { + retains.push(environment.retain(operation)); + } + + // Run GC + store.__gc(); + + if (numRetainedReferences > 0) { + // The data is still retained, so cleanup should not have happened + expect(unsubscribeMock).not.toHaveBeenCalled(); + } else { + // The data is not retained, cleanup should have happened + expect(unsubscribeMock).toHaveBeenCalledTimes(1); + } + + // Dispose of the retains + for (const retain of retains) { + retain.dispose(); + } + + // Run GC again to ensure cleanup happens after disposing retains + store.__gc(); + + // Now, cleanup should have happened if it didn't before + expect(unsubscribeMock).toHaveBeenCalledTimes(1); + + // Cleanup the spy + subscribeSpy.mockRestore(); + }, +); + type TestProps = { query: ConcreteRequest, variables: VariablesOf, diff --git a/packages/relay-runtime/store/__tests__/resolvers/TodoModel.js b/packages/relay-runtime/store/__tests__/resolvers/TodoModel.js index d022ad573c3bb..ee454ec18f3bd 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/TodoModel.js +++ b/packages/relay-runtime/store/__tests__/resolvers/TodoModel.js @@ -11,6 +11,7 @@ 'use strict'; +import type {TestResolverContextType} from '../../../mutations/__tests__/TestResolverContextType'; import type {TodoModelCapitalizedID$key} from './__generated__/TodoModelCapitalizedID.graphql'; import type {TodoModelCapitalizedIDLegacy$key} from './__generated__/TodoModelCapitalizedIDLegacy.graphql'; import type {TodoDescription} from './TodoDescription'; @@ -50,6 +51,17 @@ function description(model: TodoModelType): ?string { return model?.description; } +/** + * @RelayResolver TodoModel.another_value_from_context: String + */ +function another_value_from_context( + model: TodoModelType, + _: mixed, + context: TestResolverContextType, +): ?string { + return context?.greeting.myHello; +} + /** * @RelayResolver TodoModel.capitalized_id: String * @rootFragment TodoModelCapitalizedID @@ -180,6 +192,7 @@ module.exports = { todo_model_null, TodoModel, description, + another_value_from_context, fancy_description, fancy_description_null, fancy_description_suspends, diff --git a/packages/relay-runtime/store/__tests__/resolvers/UserAgeResolvers.js b/packages/relay-runtime/store/__tests__/resolvers/UserAgeResolvers.js new file mode 100644 index 0000000000000..745b23aa7608d --- /dev/null +++ b/packages/relay-runtime/store/__tests__/resolvers/UserAgeResolvers.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @RelayResolver User.age: Int + */ +function age(_: mixed, context: { age: number }): number { + return context.age; +} + +module.exports = { + age, +}; diff --git a/packages/relay-runtime/store/__tests__/resolvers/__generated__/BaseCounter____relay_model_instance.graphql.js b/packages/relay-runtime/store/__tests__/resolvers/__generated__/BaseCounter____relay_model_instance.graphql.js new file mode 100644 index 0000000000000..cc8482d44955e --- /dev/null +++ b/packages/relay-runtime/store/__tests__/resolvers/__generated__/BaseCounter____relay_model_instance.graphql.js @@ -0,0 +1,61 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<7a18458e8e74a97968fd3346963dee05>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { BaseCounter } from "../LiveCounterContextResolver.js"; +import type { FragmentType } from "relay-runtime"; +declare export opaque type BaseCounter____relay_model_instance$fragmentType: FragmentType; +export type BaseCounter____relay_model_instance$data = {| + +__relay_model_instance: BaseCounter, + +$fragmentType: BaseCounter____relay_model_instance$fragmentType, +|}; +export type BaseCounter____relay_model_instance$key = { + +$data?: BaseCounter____relay_model_instance$data, + +$fragmentSpreads: BaseCounter____relay_model_instance$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "BaseCounter____relay_model_instance", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__relay_model_instance", + "storageKey": null + } + ] + } + ], + "type": "BaseCounter", + "abstractKey": null +}; + +module.exports = ((node/*: any*/)/*: Fragment< + BaseCounter____relay_model_instance$fragmentType, + BaseCounter____relay_model_instance$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/resolvers/__generated__/ResolverGCTestNoRetainedQueriesQuery.graphql.js b/packages/relay-runtime/store/__tests__/resolvers/__generated__/ResolverGCTestNoRetainedQueriesQuery.graphql.js new file mode 100644 index 0000000000000..18432b4d6ee1c --- /dev/null +++ b/packages/relay-runtime/store/__tests__/resolvers/__generated__/ResolverGCTestNoRetainedQueriesQuery.graphql.js @@ -0,0 +1,103 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @oncall relay + * + * @generated SignedSource<<5f279865ba329845f19bc4bed597d3b5>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ClientRequest, ClientQuery } from 'relay-runtime'; +import type { LiveState } from "relay-runtime"; +import {counter_no_fragment as queryCounterNoFragmentResolverType} from "../LiveCounterNoFragment.js"; +import type { TestResolverContextType } from "../../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `queryCounterNoFragmentResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(queryCounterNoFragmentResolverType: ( + args: void, + context: TestResolverContextType, +) => LiveState); +export type ResolverGCTestNoRetainedQueriesQuery$variables = {||}; +export type ResolverGCTestNoRetainedQueriesQuery$data = {| + +counter_no_fragment: ?number, +|}; +export type ResolverGCTestNoRetainedQueriesQuery = {| + response: ResolverGCTestNoRetainedQueriesQuery$data, + variables: ResolverGCTestNoRetainedQueriesQuery$variables, +|}; +*/ + +var node/*: ClientRequest*/ = { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "ResolverGCTestNoRetainedQueriesQuery", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "fragment": null, + "kind": "RelayLiveResolver", + "name": "counter_no_fragment", + "resolverModule": require('./../LiveCounterNoFragment').counter_no_fragment, + "path": "counter_no_fragment" + } + ] + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "ResolverGCTestNoRetainedQueriesQuery", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "name": "counter_no_fragment", + "args": null, + "fragment": null, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + } + ] + } + ] + }, + "params": { + "cacheID": "a5905620d7505500bf0cb987c540bc24", + "id": null, + "metadata": {}, + "name": "ResolverGCTestNoRetainedQueriesQuery", + "operationKind": "query", + "text": null + } +}; + +if (__DEV__) { + (node/*: any*/).hash = "c081f9d7220711c53528ae28f136ca80"; +} + +module.exports = ((node/*: any*/)/*: ClientQuery< + ResolverGCTestNoRetainedQueriesQuery$variables, + ResolverGCTestNoRetainedQueriesQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAlwaysThrowsResolver.graphql.js b/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAlwaysThrowsResolver.graphql.js index fb62796ae5f57..44c530d8f4e21 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAlwaysThrowsResolver.graphql.js +++ b/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAlwaysThrowsResolver.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<65000cc0a4b69bdffd1ff81454a9ea5e>> + * @generated SignedSource<<46c82d1a963162cda03157ec67d447fa>> * @flow * @lightSyntaxTransform * @nogrep @@ -23,11 +23,6 @@ declare export opaque type UserAlwaysThrowsResolver$fragmentType: FragmentType; export type UserAlwaysThrowsResolver$data = {| +__typename: "User", +$fragmentType: UserAlwaysThrowsResolver$fragmentType, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$fragmentType: UserAlwaysThrowsResolver$fragmentType, |}; export type UserAlwaysThrowsResolver$key = { +$data?: UserAlwaysThrowsResolver$data, diff --git a/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAnotherClientEdgeResolver.graphql.js b/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAnotherClientEdgeResolver.graphql.js index 5460b0f18008e..b3defaa980d19 100644 --- a/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAnotherClientEdgeResolver.graphql.js +++ b/packages/relay-runtime/store/__tests__/resolvers/__generated__/UserAnotherClientEdgeResolver.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<5d8624f4c97bb474b71fe652707728bc>> + * @generated SignedSource<<9b561042e59b39b66fc334d8324c0d70>> * @flow * @lightSyntaxTransform * @nogrep @@ -23,11 +23,6 @@ declare export opaque type UserAnotherClientEdgeResolver$fragmentType: FragmentT export type UserAnotherClientEdgeResolver$data = {| +__typename: "User", +$fragmentType: UserAnotherClientEdgeResolver$fragmentType, -|} | {| - // This will never be '%other', but we need some - // value in case none of the concrete values match. - +__typename: "%other", - +$fragmentType: UserAnotherClientEdgeResolver$fragmentType, |}; export type UserAnotherClientEdgeResolver$key = { +$data?: UserAnotherClientEdgeResolver$data, diff --git a/packages/relay-runtime/store/__tests__/waitForFragmentData-test.js b/packages/relay-runtime/store/__tests__/waitForFragmentData-test.js index ec64390dd1a92..456725cd381d4 100644 --- a/packages/relay-runtime/store/__tests__/waitForFragmentData-test.js +++ b/packages/relay-runtime/store/__tests__/waitForFragmentData-test.js @@ -52,6 +52,39 @@ test('data ok', async () => { expect(result).toEqual({name: 'Elizabeth'}); }); +test('data ok with plural fragment', async () => { + const query = graphql` + query waitForFragmentDataTestOkPluralQuery { + nodes(ids: ["1", "2"]) { + ...waitForFragmentDataTestOkPluralFragment + } + } + `; + + const fragment = graphql` + fragment waitForFragmentDataTestOkPluralFragment on User + @relay(plural: true) { + name + } + `; + + const environment = createMockEnvironment({ + store: new LiveResolverStore(new RelayRecordSource()), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + {id: '1', __typename: 'User', name: 'Alice'}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }); + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe - data is untyped + const result = await waitForFragmentData(environment, fragment, data.nodes); + expect(result).toEqual([{name: 'Alice'}, {name: 'Bob'}]); +}); + test('Promise rejects with @throwOnFieldError', async () => { const query = graphql` query waitForFragmentDataTestThrowOnFieldErrorQuery { @@ -83,7 +116,7 @@ test('Promise rejects with @throwOnFieldError', async () => { result = e; } expect(result?.message).toEqual( - "Relay: Resolver error at path 'always_throws' in 'waitForFragmentDataTestResolverErrorWithThrowOnFieldErrorFragment'.", + "Relay: Resolver error at path 'always_throws' in 'waitForFragmentDataTestResolverErrorWithThrowOnFieldErrorFragment'. Message: I always throw. What did you expect?", ); }); diff --git a/packages/relay-runtime/store/createRelayContext.js b/packages/relay-runtime/store/createRelayContext.js index 87074907d1a10..82ac5551936c4 100644 --- a/packages/relay-runtime/store/createRelayContext.js +++ b/packages/relay-runtime/store/createRelayContext.js @@ -12,6 +12,7 @@ 'use strict'; import type {RelayContext} from './RelayStoreTypes.js'; +import type {Context} from 'react'; import typeof {createContext} from 'react'; const invariant = require('invariant'); @@ -24,10 +25,10 @@ type React = $ReadOnly<{ ... }>; -let relayContext: ?React$Context; +let relayContext: ?Context; let firstReact: ?React; -function createRelayContext(react: React): React$Context { +function createRelayContext(react: React): Context { if (!relayContext) { relayContext = react.createContext(null); if (__DEV__) { diff --git a/packages/relay-runtime/store/generateTypenamePrefixedDataID.js b/packages/relay-runtime/store/generateTypenamePrefixedDataID.js new file mode 100644 index 0000000000000..ddf4df9b80a19 --- /dev/null +++ b/packages/relay-runtime/store/generateTypenamePrefixedDataID.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall relay + */ + +'use strict'; + +import type {DataID} from 'relay-runtime/util/RelayRuntimeTypes'; + +const TYPENAME_PREFIX = '__type:'; + +function generateTypenamePrefixedDataID( + typeName: string, + dataID: DataID, +): DataID { + return `${TYPENAME_PREFIX}${typeName}:${dataID}`; +} + +module.exports = {generateTypenamePrefixedDataID}; diff --git a/packages/relay-runtime/store/live-resolvers/LiveResolverCache.js b/packages/relay-runtime/store/live-resolvers/LiveResolverCache.js index c36b546f6f3cc..6003b5315a14f 100644 --- a/packages/relay-runtime/store/live-resolvers/LiveResolverCache.js +++ b/packages/relay-runtime/store/live-resolvers/LiveResolverCache.js @@ -48,6 +48,7 @@ const { RELAY_RESOLVER_OUTPUT_TYPE_RECORD_IDS, RELAY_RESOLVER_SNAPSHOT_KEY, RELAY_RESOLVER_VALUE_KEY, + getReadTimeResolverStorageKey, getStorageKey, } = require('../RelayStoreUtils'); const getOutputTypeRecordIDs = require('./getOutputTypeRecordIDs'); @@ -129,7 +130,7 @@ class LiveResolverCache implements ResolverCache { // resolvers on this parent record. const record = expectRecord(recordSource, recordID); - const storageKey = getStorageKey(field, variables); + const storageKey = getReadTimeResolverStorageKey(field, variables); let linkedID = RelayModernRecord.getLinkedRecordID(record, storageKey); let linkedRecord = linkedID == null ? null : recordSource.get(linkedID); diff --git a/packages/relay-runtime/store/live-resolvers/resolverDataInjector.js b/packages/relay-runtime/store/live-resolvers/resolverDataInjector.js index 09521911a7df0..072913311489c 100644 --- a/packages/relay-runtime/store/live-resolvers/resolverDataInjector.js +++ b/packages/relay-runtime/store/live-resolvers/resolverDataInjector.js @@ -12,12 +12,12 @@ 'use strict'; import type {Fragment} from '../../util/RelayRuntimeTypes'; -import type {FragmentType} from '../RelayStoreTypes'; +import type {FragmentType, ResolverContext} from '../RelayStoreTypes'; const {readFragment} = require('../ResolverFragments'); const invariant = require('invariant'); -type ResolverFn = ($FlowFixMe, ?$FlowFixMe) => mixed; +type ResolverFn = ($FlowFixMe, ?$FlowFixMe, ResolverContext) => mixed; /** * @@ -40,7 +40,11 @@ function resolverDataInjector( isRequiredField?: boolean, ): (fragmentKey: TFragmentType, args: mixed) => mixed { const resolverFn: ResolverFn = _resolverFn; - return (fragmentKey: TFragmentType, args: mixed): mixed => { + return ( + fragmentKey: TFragmentType, + args: mixed, + resolverContext: ResolverContext, + ): mixed => { const data = readFragment(fragment, fragmentKey); if (fieldName != null) { if (data == null) { @@ -52,7 +56,7 @@ function resolverDataInjector( fragment.name, ); } else { - return resolverFn(null, args); + return resolverFn(null, args, resolverContext); // TODO: This statement does not seem to be covered by a test? } } @@ -70,7 +74,7 @@ function resolverDataInjector( } // $FlowFixMe[invalid-computed-prop] - return resolverFn(data[fieldName], args); + return resolverFn(data[fieldName], args, resolverContext); } else { // If both `data` and `fieldName` is available, we expect the // `fieldName` field in the `data` object. @@ -83,7 +87,7 @@ function resolverDataInjector( } } else { // By default we will pass the full set of the fragment data to the resolver - return resolverFn(data, args); + return resolverFn(null, args, resolverContext); // TODO: This statement does not seem to be covered by a test? } }; } diff --git a/packages/relay-runtime/store/observeFragmentExperimental.js b/packages/relay-runtime/store/observeFragmentExperimental.js index e84a00855c944..68ed41452f237 100644 --- a/packages/relay-runtime/store/observeFragmentExperimental.js +++ b/packages/relay-runtime/store/observeFragmentExperimental.js @@ -9,7 +9,7 @@ * @oncall relay */ -import type {RequestDescriptor} from './RelayStoreTypes'; +import type {PluralReaderSelector, RequestDescriptor} from './RelayStoreTypes'; import type { Fragment, FragmentType, @@ -20,8 +20,8 @@ import type { } from 'relay-runtime'; const Observable = require('../network/RelayObservable'); +const {getObservableForActiveRequest} = require('../query/fetchQueryInternal'); const {getFragment} = require('../query/GraphQLTag'); -const getPendingOperationsForFragment = require('../util/getPendingOperationsForFragment'); const { handlePotentialSnapshotErrors, } = require('../util/handlePotentialSnapshotErrors'); @@ -47,8 +47,7 @@ export type HasSpread = { /** * EXPERIMENTAL: This API is experimental and does not yet support all Relay - * features. Notably, it does not correectly handle plural fragments or some - * features of Relay Resolvers. + * features. Notably, it does not correctly handle some features of Relay Resolvers. * * Given a fragment and a fragment reference, returns a promise that resolves * once the fragment data is available, or rejects if the fragment has an error. @@ -63,7 +62,9 @@ export type HasSpread = { async function waitForFragmentData( environment: IEnvironment, fragment: Fragment, - fragmentRef: HasSpread, + fragmentRef: + | HasSpread + | $ReadOnlyArray>, ): Promise { let subscription: ?Subscription; @@ -94,13 +95,14 @@ async function waitForFragmentData( declare function observeFragment( environment: IEnvironment, fragment: Fragment, - fragmentRef: HasSpread, + fragmentRef: + | HasSpread + | $ReadOnlyArray>, ): Observable>; /** * EXPERIMENTAL: This API is experimental and does not yet support all Relay - * features. Notably, it does not correectly handle plural fragments or some - * features of Relay Resolvers. + * features. Notably, it does not correctly handle some features of Relay Resolvers. * * Given a fragment and a fragment reference, returns an observable that emits * the state of the fragment over time. The observable will emit the following @@ -114,7 +116,7 @@ function observeFragment( environment: IEnvironment, fragment: Fragment, fragmentRef: mixed, -): Observable> { +): mixed { const fragmentNode = getFragment(fragment); const fragmentSelector = getSelector(fragmentNode, fragmentRef); invariant( @@ -124,24 +126,19 @@ function observeFragment( invariant(fragmentSelector != null, 'Expected a selector, got null.'); switch (fragmentSelector.kind) { case 'SingularReaderSelector': - return observeSelector(environment, fragment, fragmentSelector); + return observeSingularSelector(environment, fragment, fragmentSelector); case 'PluralReaderSelector': { - // TODO: We could use something like this RXJS's combineLatest to create - // an observable for each selector and merge them. - // https://github.com/ReactiveX/rxjs/blob/master/packages/rxjs/src/internal/observable/combineLatest.ts - // - // Note that this problem is a bit tricky because Relay currently only - // lets you subscribe at a singular fragment granularity. This makes it - // hard to batch updates such that when a store update causes multiple - // fragments to change, we can only publish a single update to the - // fragment owner. - invariant(false, 'Plural fragments are not supported'); + return observePluralSelector( + environment, + (fragment: $FlowFixMe), + fragmentSelector, + ); } } invariant(false, 'Unsupported fragment selector kind'); } -function observeSelector( +function observeSingularSelector( environment: IEnvironment, fragmentNode: Fragment, fragmentSelector: SingularReaderSelector, @@ -173,6 +170,49 @@ function observeSelector( }); } +function observePluralSelector< + TFragmentType: FragmentType, + TData: Array, +>( + environment: IEnvironment, + fragmentNode: Fragment, + fragmentSelector: PluralReaderSelector, +): Observable> { + const snapshots = fragmentSelector.selectors.map(selector => + environment.lookup(selector), + ); + + return Observable.create(sink => { + // This array is mutable since each subscription updates the array in place. + const states = snapshots.map((snapshot, index) => + snapshotToFragmentState( + environment, + fragmentNode, + fragmentSelector.selectors[index].owner, + snapshot, + ), + ); + + sink.next((mergeFragmentStates(states): $FlowFixMe)); + + const subscriptions = snapshots.map((snapshot, index) => + environment.subscribe(snapshot, latestSnapshot => { + states[index] = snapshotToFragmentState( + environment, + fragmentNode, + fragmentSelector.selectors[index].owner, + latestSnapshot, + ); + // This doesn't batch updates, so it will notify the subscriber multiple times + // if a store update impacting multiple items in the list is published. + sink.next((mergeFragmentStates(states): $FlowFixMe)); + }), + ); + + return () => subscriptions.forEach(subscription => subscription.dispose()); + }); +} + function snapshotToFragmentState( environment: IEnvironment, fragmentNode: Fragment, @@ -201,18 +241,18 @@ function snapshotToFragmentState( } if (snapshot.isMissingData) { - const pendingOperations = getPendingOperationsForFragment( - environment, - fragmentNode, - owner, - ); - if (pendingOperations != null) { + if ( + getObservableForActiveRequest(environment, owner) != null || + environment + .getOperationTracker() + .getPendingOperationsAffectingOwner(owner) != null + ) { return {state: 'loading'}; } } try { - handlePotentialSnapshotErrors(environment, snapshot.errorResponseFields); + handlePotentialSnapshotErrors(environment, snapshot.fieldErrors); } catch (error) { return {error, state: 'error'}; } @@ -229,6 +269,20 @@ function snapshotToFragmentState( return {state: 'ok', value: (snapshot.data: $FlowFixMe)}; } +function mergeFragmentStates( + states: $ReadOnlyArray>, +): FragmentState> { + const value = []; + for (const state of states) { + if (state.state === 'ok') { + value.push(state.value); + } else { + return state; + } + } + return {state: 'ok', value}; +} + module.exports = { observeFragment, waitForFragmentData, diff --git a/packages/relay-runtime/store/waitForFragmentExperimental.js b/packages/relay-runtime/store/waitForFragmentExperimental.js index 53ba061e85ec5..e1ad597178d86 100644 --- a/packages/relay-runtime/store/waitForFragmentExperimental.js +++ b/packages/relay-runtime/store/waitForFragmentExperimental.js @@ -21,8 +21,7 @@ const {observeFragment} = require('./observeFragmentExperimental'); /** * EXPERIMENTAL: This API is experimental and does not yet support all Relay - * features. Notably, it does not correectly handle plural fragments or some - * features of Relay Resolvers. + * features. Notably, it does not correctly handle some features of Relay Resolvers. * * Given a fragment and a fragment reference, returns a promise that resolves * once the fragment data is available, or rejects if the fragment has an error. @@ -37,7 +36,9 @@ const {observeFragment} = require('./observeFragmentExperimental'); async function waitForFragmentData( environment: IEnvironment, fragment: Fragment, - fragmentRef: HasSpread, + fragmentRef: + | HasSpread + | $ReadOnlyArray>, ): Promise { let subscription: ?Subscription; diff --git a/packages/relay-runtime/subscription/__tests__/requestSubscription-test.js b/packages/relay-runtime/subscription/__tests__/requestSubscription-test.js index 3aed57af6c441..9bdf5c01177a7 100644 --- a/packages/relay-runtime/subscription/__tests__/requestSubscription-test.js +++ b/packages/relay-runtime/subscription/__tests__/requestSubscription-test.js @@ -10,6 +10,7 @@ */ 'use strict'; +import type {DeclarativeMutationConfig} from '../../mutations/RelayDeclarativeMutationConfig'; import type {GraphQLResponse} from '../../network/RelayNetworkTypes'; import type {RecordSourceSelectorProxy} from '../../store/RelayStoreTypes'; import type {RequestParameters} from '../../util/RelayConcreteNode'; @@ -109,7 +110,7 @@ describe('requestSubscription-test', () => { } `; - const configs = [ + const configs: DeclarativeMutationConfig[] = [ { type: 'RANGE_ADD', connectionName: 'comments', diff --git a/packages/relay-runtime/util/NormalizationNode.js b/packages/relay-runtime/util/NormalizationNode.js index de2efe45742e1..d2a818d9b1da1 100644 --- a/packages/relay-runtime/util/NormalizationNode.js +++ b/packages/relay-runtime/util/NormalizationNode.js @@ -12,7 +12,7 @@ 'use strict'; import type {ResolverFunction, ResolverModule} from './ReaderNode'; -import type {ConcreteRequest} from './RelayConcreteNode'; +import type {ConcreteRequest, ProvidedVariableType} from './RelayConcreteNode'; import type {JSResourceReference} from 'JSResourceReference'; /** @@ -28,6 +28,7 @@ export type NormalizationOperation = { +[string]: $ReadOnlyArray, }, +use_exec_time_resolvers?: boolean, + +exec_time_resolvers_enabled_provider?: ProvidedVariableType, }; export type NormalizationHandle = diff --git a/packages/relay-runtime/util/RelayConcreteNode.js b/packages/relay-runtime/util/RelayConcreteNode.js index bf50490cbef93..0a8c591b54b61 100644 --- a/packages/relay-runtime/util/RelayConcreteNode.js +++ b/packages/relay-runtime/util/RelayConcreteNode.js @@ -39,6 +39,8 @@ export type NormalizationRootNode = | ConcreteRequest | NormalizationSplitOperation; +export type ProvidedVariableType = {get(): mixed}; + export type ProvidedVariablesType = {+[key: string]: {get(): mixed}}; /** diff --git a/packages/relay-runtime/util/RelayFeatureFlags.js b/packages/relay-runtime/util/RelayFeatureFlags.js index 91d5ff2672d62..75a200bc9e999 100644 --- a/packages/relay-runtime/util/RelayFeatureFlags.js +++ b/packages/relay-runtime/util/RelayFeatureFlags.js @@ -58,6 +58,18 @@ export type FeatureFlags = { // Adds a prefix to the storage key of read time resolvers. This is used to // disambiguate the same resolver being used at both read time and exec time. ENABLE_READ_TIME_RESOLVER_STORAGE_KEY_PREFIX: boolean, + + // Enable the fix for usePaginationFragment stucking in loading state + ENABLE_USE_PAGINATION_IS_LOADING_FIX: boolean, + + // Enable logging an ID collision in the Relay store + ENABLE_STORE_ID_COLLISION_LOGGING: boolean, + + // Throw on nested store updates + DISALLOW_NESTED_UPDATES: boolean, + + // Enable prefixing of DataID in the store with __typename + ENABLE_TYPENAME_PREFIXED_DATA_ID: boolean, }; const RelayFeatureFlags: FeatureFlags = { @@ -72,6 +84,7 @@ const RelayFeatureFlags: FeatureFlags = { MAX_DATA_ID_LENGTH: null, STRING_INTERN_LEVEL: 0, LOG_MISSING_RECORDS_IN_PROD: false, + ENABLE_STORE_ID_COLLISION_LOGGING: false, ENABLE_NONCOMPLIANT_ERROR_HANDLING_ON_LISTS: false, ENABLE_LOOSE_SUBSCRIPTION_ATTRIBUTION: false, ENABLE_OPERATION_TRACKER_OPTIMISTIC_UPDATES: false, @@ -81,6 +94,9 @@ const RelayFeatureFlags: FeatureFlags = { ENABLE_CYLE_DETECTION_IN_VARIABLES: false, ENABLE_ACTIVITY_COMPATIBILITY: false, ENABLE_READ_TIME_RESOLVER_STORAGE_KEY_PREFIX: true, + ENABLE_USE_PAGINATION_IS_LOADING_FIX: false, + DISALLOW_NESTED_UPDATES: false, + ENABLE_TYPENAME_PREFIXED_DATA_ID: false, }; module.exports = RelayFeatureFlags; diff --git a/packages/relay-runtime/util/RelayRuntimeTypes.js b/packages/relay-runtime/util/RelayRuntimeTypes.js index c7179cfae539e..79a221046a6be 100644 --- a/packages/relay-runtime/util/RelayRuntimeTypes.js +++ b/packages/relay-runtime/util/RelayRuntimeTypes.js @@ -53,9 +53,10 @@ export type VariablesOf = T['variables']; * state of any configured response cache. * - `poll`: causes a query to live update by polling at the specified interval * in milliseconds. (This value will be passed to setTimeout.) - * - `liveConfigId`: causes a query to live update by calling GraphQLLiveQuery, - * it represents a configuration of gateway when doing live query - * - `onSubscribe`: Not in use. + * - `liveConfigId`: Makes a query live by sending through RTI stack. + * - `onSubscribe`: Callback to be called when a live query stream is started. + * - `onPause`: Callback to be called when a live query stream is paused, e.g. due to a network disconnection. + * - `onResume`: Callback to be called when a live query stream is resumed, e.g. from a network disconnection. * - `metadata`: user-supplied metadata. * - `transactionId`: a user-supplied value, intended for use as a unique id for * a given instance of executing an operation. @@ -65,6 +66,8 @@ export type CacheConfig = { poll?: ?number, liveConfigId?: ?string, onSubscribe?: () => void, + onResume?: (pauseTimeMs: number) => void, + onPause?: (mqttConnectionIsOk: boolean, internetIsOk: boolean) => void, metadata?: {[key: string]: mixed, ...}, transactionId?: ?string, }; diff --git a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQuery.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQuery.graphql.js index 636bc49292310..ebdee63c602e4 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQuery.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<1354180d9df58b0704c83b17a43fb95f>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a6ebfafd3adccdfde2e43998af09c190"; + (node/*: any*/).hash = "18064784693e9788fe52f1bbae385ee0"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQueryWithArgsQuery.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQueryWithArgsQuery.graphql.js index 52a02d6a72122..7b8c876201750 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQueryWithArgsQuery.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTest1UserQueryWithArgsQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<<13674f5f22576daad7c1bf3df650b42c>> * @flow * @lightSyntaxTransform * @nogrep @@ -177,7 +177,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "2c6734517dd2de88716f70f4c2a3b59e"; + (node/*: any*/).hash = "608b70474f7b066bac350843e1dd58c6"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQuery.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQuery.graphql.js index 04a0c9142c5ad..eb813fc962ad8 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQuery.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6d05a0a55ccd1745dfdaa1439e03cd61>> + * @generated SignedSource<<2474e6b61cea3140e05b74f7be798603>> * @flow * @lightSyntaxTransform * @nogrep @@ -171,7 +171,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "0109159e3a59848d6da59a0b19147157"; + (node/*: any*/).hash = "3e1de67e9c815581b0b170f37d56a100"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQueryWithArgsQuery.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQueryWithArgsQuery.graphql.js index afa5171093a84..b9202ac38428e 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQueryWithArgsQuery.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/getFragmentIdentifierTestUserQueryWithArgsQuery.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<313d4d202ed7f617972df191239b7378>> + * @generated SignedSource<<8cd3dc9de6099bff154fa4911de1a39c>> * @flow * @lightSyntaxTransform * @nogrep @@ -177,7 +177,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "146115816909f480fcbd194b3816899f"; + (node/*: any*/).hash = "ce1c117df7e611604494cc0036258270"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest1Query.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest1Query.graphql.js index ab2803ec94c86..5e1822d318e22 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest1Query.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest1Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<6703998458a25903621ee13227354a96>> + * @generated SignedSource<<6c9eb37f21f0baf7aaa87dd9c30830b9>> * @flow * @lightSyntaxTransform * @nogrep @@ -158,7 +158,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a613af5829765dd939e03fd6ff1141ff"; + (node/*: any*/).hash = "c5f46e63be71ffd76d40c58b53dc2c3a"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest2Query.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest2Query.graphql.js index 7b51233673ed9..2b41af9a2501c 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest2Query.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest2Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<28b3eba1bf961281a612ddc50ead4b1f>> + * @generated SignedSource<<737fdcf3efeda362abcc16035263cb89>> * @flow * @lightSyntaxTransform * @nogrep @@ -181,7 +181,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "e9e93574d0f69b01f4abac7b2738cece"; + (node/*: any*/).hash = "672d458b4f030a73c4aeb0146485c476"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest3Query.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest3Query.graphql.js index eb7961d1bd5cc..b78b4d4a446bb 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest3Query.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest3Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<5815185ccc4d1a85d36ed17b4f10ec0d>> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -182,7 +182,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "a0300c848560c03d4f2d7662ab5d27d3"; + (node/*: any*/).hash = "e9f1d13b64d707716ef131a7ec5c3ca0"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest4Query.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest4Query.graphql.js index 6dd528e418ba3..64cc79c8290b8 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest4Query.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest4Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<> + * @generated SignedSource<> * @flow * @lightSyntaxTransform * @nogrep @@ -214,7 +214,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "08096779ec00305df9771824e002669c"; + (node/*: any*/).hash = "b5809a8936443db3f6696119fe66e3ed"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest5Query.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest5Query.graphql.js index d2216f8272afa..9579c61ced3a2 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest5Query.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest5Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<9f59b2fcd357e043b5d5fa94238f3fe2>> + * @generated SignedSource<<54851b122a1aa482e5b940cdad956dba>> * @flow * @lightSyntaxTransform * @nogrep @@ -185,7 +185,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "b9da4aca44074152f72d5208416421af"; + (node/*: any*/).hash = "fea93f1b453b7ed30e1b62dc0b32bc4e"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest6Query.graphql.js b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest6Query.graphql.js index 6b3d98efd465a..8ac65ec2d0d70 100644 --- a/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest6Query.graphql.js +++ b/packages/relay-runtime/util/__tests__/__generated__/withProvidedVariablesTest6Query.graphql.js @@ -6,7 +6,7 @@ * * @oncall relay * - * @generated SignedSource<<33a7c304a92c212c1292fd71495c8cb8>> + * @generated SignedSource<<0c545f68f0cf0f075ac81fc1d2845f21>> * @flow * @lightSyntaxTransform * @nogrep @@ -158,7 +158,7 @@ return { })(); if (__DEV__) { - (node/*: any*/).hash = "8c7f3de6f49184530628833ac9970eef"; + (node/*: any*/).hash = "4f2c4062537ffda1cddd4cb6b75b6bfa"; } module.exports = ((node/*: any*/)/*: Query< diff --git a/packages/relay-runtime/util/__tests__/getFragmentIdentifier-test.js b/packages/relay-runtime/util/__tests__/getFragmentIdentifier-test.js index 669f13b53b49d..25e3c7d8ef4d9 100644 --- a/packages/relay-runtime/util/__tests__/getFragmentIdentifier-test.js +++ b/packages/relay-runtime/util/__tests__/getFragmentIdentifier-test.js @@ -51,7 +51,7 @@ describe('getFragmentIdentifier', () => { gqlSingularQuery = graphql` query getFragmentIdentifierTestUserQuery($id: ID!, $scale: Float!) { node(id: $id) { - ...getFragmentIdentifierTestUserFragment + ...getFragmentIdentifierTestUserFragment @dangerously_unaliased_fixme } } `; @@ -62,6 +62,7 @@ describe('getFragmentIdentifier', () => { ) { node(id: $id) { ...getFragmentIdentifierTestUserFragmentWithArgs + @dangerously_unaliased_fixme @arguments(scaleLocal: $scale) } } @@ -229,7 +230,7 @@ describe('getFragmentIdentifier Optimized', () => { gqlSingularQuery = graphql` query getFragmentIdentifierTest1UserQuery($id: ID!, $scale: Float!) { node(id: $id) { - ...getFragmentIdentifierTest1UserFragment + ...getFragmentIdentifierTest1UserFragment @dangerously_unaliased_fixme } } `; @@ -241,6 +242,7 @@ describe('getFragmentIdentifier Optimized', () => { ) { node(id: $id) { ...getFragmentIdentifierTest1UserFragmentWithArgs + @dangerously_unaliased_fixme @arguments(scaleLocal: $scale) } } diff --git a/packages/relay-runtime/util/__tests__/getPaginationVariables-test.js b/packages/relay-runtime/util/__tests__/getPaginationVariables-test.js index 3e21c5227a658..a124c75038677 100644 --- a/packages/relay-runtime/util/__tests__/getPaginationVariables-test.js +++ b/packages/relay-runtime/util/__tests__/getPaginationVariables-test.js @@ -11,10 +11,12 @@ 'use strict'; +import type {Direction} from '../getPaginationVariables'; + const getPaginationVariables = require('../getPaginationVariables'); describe('getPaginationVariables', () => { - let direction; + let direction: Direction; describe('forward', () => { beforeEach(() => { diff --git a/packages/relay-runtime/util/__tests__/handlePotentialSnapshotErrors-test.js b/packages/relay-runtime/util/__tests__/handlePotentialSnapshotErrors-test.js index 60a6b51e6549a..7882c20a6a11b 100644 --- a/packages/relay-runtime/util/__tests__/handlePotentialSnapshotErrors-test.js +++ b/packages/relay-runtime/util/__tests__/handlePotentialSnapshotErrors-test.js @@ -387,7 +387,7 @@ describe('handlePotentialSnapshotErrors', () => { }, ]); }).toThrowError( - /^Relay: Resolver error at path 'testPath' in 'testOwner'/, + "Relay: Resolver error at path 'testPath' in 'testOwner'. Message: testError", ); expect(relayFieldLogger).toHaveBeenCalledTimes(1); diff --git a/packages/relay-runtime/util/__tests__/withProvidedVariables-test.js b/packages/relay-runtime/util/__tests__/withProvidedVariables-test.js index 7d32e9160bbae..cbc0f93525e59 100644 --- a/packages/relay-runtime/util/__tests__/withProvidedVariables-test.js +++ b/packages/relay-runtime/util/__tests__/withProvidedVariables-test.js @@ -26,7 +26,7 @@ describe('withProvidedVariables', () => { const userQuery = graphql` query withProvidedVariablesTest1Query { node(id: 4) { - ...withProvidedVariablesTest1Fragment + ...withProvidedVariablesTest1Fragment @dangerously_unaliased_fixme } } `; @@ -62,6 +62,7 @@ describe('withProvidedVariables', () => { query withProvidedVariablesTest2Query($includeFriendsCount: Boolean!) { node(id: 4) { ...withProvidedVariablesTest2Fragment + @dangerously_unaliased_fixme @arguments(includeFriendsCount_: $includeFriendsCount) } } @@ -99,7 +100,7 @@ describe('withProvidedVariables', () => { const userQuery = graphql` query withProvidedVariablesTest3Query { node(id: 4) { - ...withProvidedVariablesTest3Fragment + ...withProvidedVariablesTest3Fragment @dangerously_unaliased_fixme } } `; @@ -142,8 +143,8 @@ describe('withProvidedVariables', () => { const userQuery = graphql` query withProvidedVariablesTest4Query { node(id: 4) { - ...withProvidedVariablesTest4Fragment1 - ...withProvidedVariablesTest4Fragment2 + ...withProvidedVariablesTest4Fragment1 @dangerously_unaliased_fixme + ...withProvidedVariablesTest4Fragment2 @dangerously_unaliased_fixme } } `; @@ -203,7 +204,7 @@ describe('withProvidedVariables', () => { const userQuery = graphql` query withProvidedVariablesTest5Query { node(id: 4) { - ...withProvidedVariablesTest5Fragment + ...withProvidedVariablesTest5Fragment @dangerously_unaliased_fixme } } `; @@ -269,7 +270,7 @@ describe('withProvidedVariables', () => { const userQuery = graphql` query withProvidedVariablesTest6Query { node(id: 4) { - ...withProvidedVariablesTest6Fragment + ...withProvidedVariablesTest6Fragment @dangerously_unaliased_fixme } } `; diff --git a/packages/relay-runtime/util/getPaginationVariables.js b/packages/relay-runtime/util/getPaginationVariables.js index a38fb729463dd..7a5247bd9225e 100644 --- a/packages/relay-runtime/util/getPaginationVariables.js +++ b/packages/relay-runtime/util/getPaginationVariables.js @@ -56,6 +56,7 @@ function getPaginationVariables( ...baseVariables, ...extraVariables, [backwardMetadata.cursor]: cursor, + // $FlowFixMe[incompatible-type] [backwardMetadata.count]: count, }; if (forwardMetadata && forwardMetadata.cursor) { @@ -92,6 +93,7 @@ function getPaginationVariables( ...baseVariables, ...extraVariables, [forwardMetadata.cursor]: cursor, + // $FlowFixMe[incompatible-type] [forwardMetadata.count]: count, }; if (backwardMetadata && backwardMetadata.cursor) { diff --git a/packages/relay-runtime/util/handlePotentialSnapshotErrors.js b/packages/relay-runtime/util/handlePotentialSnapshotErrors.js index 8e975827feec3..bdfdbfb58362f 100644 --- a/packages/relay-runtime/util/handlePotentialSnapshotErrors.js +++ b/packages/relay-runtime/util/handlePotentialSnapshotErrors.js @@ -12,8 +12,8 @@ 'use strict'; import type { - ErrorResponseField, - ErrorResponseFields, + FieldError, + FieldErrors, IEnvironment, } from '../store/RelayStoreTypes'; @@ -21,21 +21,21 @@ const invariant = require('invariant'); function handleFieldErrors( environment: IEnvironment, - errorResponseFields: ErrorResponseFields, + fieldErrors: FieldErrors, ) { - for (const fieldError of errorResponseFields) { + for (const fieldError of fieldErrors) { // First we log all events. Note that the logger may opt to throw its own // error here if it wants to throw an error that is better integrated into // site's error handling infrastructure. environment.relayFieldLogger(fieldError); } - for (const fieldError of errorResponseFields) { + for (const fieldError of fieldErrors) { if (eventShouldThrow(fieldError)) { switch (fieldError.kind) { case 'relay_resolver.error': throw new Error( - `Relay: Resolver error at path '${fieldError.fieldPath}' in '${fieldError.owner}'.`, + `Relay: Resolver error at path '${fieldError.fieldPath}' in '${fieldError.owner}'. Message: ${fieldError.error.message}`, ); case 'relay_field_payload.error': throw new Error( @@ -63,7 +63,7 @@ function handleFieldErrors( } } -function eventShouldThrow(event: ErrorResponseField): boolean { +function eventShouldThrow(event: FieldError): boolean { switch (event.kind) { case 'relay_resolver.error': case 'relay_field_payload.error': @@ -82,14 +82,14 @@ function eventShouldThrow(event: ErrorResponseField): boolean { function handlePotentialSnapshotErrors( environment: IEnvironment, - errorResponseFields: ?ErrorResponseFields, + fieldErrors: ?FieldErrors, ) { /** * Inside handleFieldErrors, we check for throwOnFieldError - but this fn logs the error anyway by default * which is why this still should run in any case there's errors. */ - if (errorResponseFields != null) { - handleFieldErrors(environment, errorResponseFields); + if (fieldErrors != null) { + handleFieldErrors(environment, fieldErrors); } } diff --git a/packages/relay-runtime/util/registerEnvironmentWithDevTools.js b/packages/relay-runtime/util/registerEnvironmentWithDevTools.js index e9a782191b154..18adf2c3ad25a 100644 --- a/packages/relay-runtime/util/registerEnvironmentWithDevTools.js +++ b/packages/relay-runtime/util/registerEnvironmentWithDevTools.js @@ -19,8 +19,10 @@ function registerEnvironmentWithDevTools(environment: IEnvironment): void { const _global = typeof global !== 'undefined' ? global - : typeof window !== 'undefined' - ? window + : // $FlowFixMe[cannot-resolve-name] + typeof window !== 'undefined' + ? // $FlowFixMe[cannot-resolve-name] + window : undefined; // $FlowFixMe[incompatible-use] D61394600 diff --git a/packages/relay-runtime/util/withStartAndDuration.js b/packages/relay-runtime/util/withStartAndDuration.js index 07dff3435095c..a3aa8fe8911c9 100644 --- a/packages/relay-runtime/util/withStartAndDuration.js +++ b/packages/relay-runtime/util/withStartAndDuration.js @@ -12,11 +12,14 @@ 'use strict'; const isPerformanceNowAvailable = + // $FlowFixMe[cannot-resolve-name] typeof window !== 'undefined' && + // $FlowFixMe[cannot-resolve-name] typeof window?.performance?.now === 'function'; function currentTimestamp(): number { if (isPerformanceNowAvailable) { + // $FlowFixMe[cannot-resolve-name] return window.performance.now(); } return Date.now(); diff --git a/packages/relay-test-utils-internal/index.js b/packages/relay-test-utils-internal/index.js index d48664138fbf2..e9d198c8511c5 100644 --- a/packages/relay-test-utils-internal/index.js +++ b/packages/relay-test-utils-internal/index.js @@ -49,6 +49,7 @@ const {createMockEnvironment, unwrapContainer} = require('relay-test-utils'); function cannotReadPropertyOfUndefined__DEPRECATED( propertyName: string, ): string { + // $FlowFixMe[cannot-resolve-name] const matches = process.version.match(/^v(\d+)\./); const majorVersion = matches == null ? null : parseInt(matches[1], 10); if (majorVersion == null || majorVersion < 16) { diff --git a/packages/relay-test-utils/RelayMockPayloadGenerator.js b/packages/relay-test-utils/RelayMockPayloadGenerator.js index 938c273fbf113..25b023befe30d 100644 --- a/packages/relay-test-utils/RelayMockPayloadGenerator.js +++ b/packages/relay-test-utils/RelayMockPayloadGenerator.js @@ -71,7 +71,7 @@ type Traversable = { +args: ?{[string]: mixed, ...}, }; type MockData = {[string]: mixed, ...}; -type MockResolverContext = { +export type MockResolverContext = { +parentType: ?string, +name: ?string, +alias: ?string, @@ -536,7 +536,9 @@ class RelayMockPayloadGenerator { mockData = { ...mockData, [TYPENAME_KEY]: typeName, + // $FlowFixMe[invalid-computed-prop] [getModuleOperationKey(documentName)]: operation.name, + // $FlowFixMe[invalid-computed-prop] [getModuleComponentKey(documentName)]: defaultValues.__module_component, ...this._traverseSelections( diff --git a/packages/relay-test-utils/__tests__/RelayMockEnvironment-test.js b/packages/relay-test-utils/__tests__/RelayMockEnvironment-test.js index 8619e7d056968..ba53bac149d00 100644 --- a/packages/relay-test-utils/__tests__/RelayMockEnvironment-test.js +++ b/packages/relay-test-utils/__tests__/RelayMockEnvironment-test.js @@ -157,7 +157,9 @@ describe('when generating multiple payloads for deferred data', () => { node(id: $id) { id ... on User { - ...RelayMockEnvironmentTestWithDeferFragment_user @defer + ...RelayMockEnvironmentTestWithDeferFragment_user + @dangerously_unaliased_fixme + @defer } } } diff --git a/packages/relay-test-utils/__tests__/RelayMockEnvironmentWithComponents-test.js b/packages/relay-test-utils/__tests__/RelayMockEnvironmentWithComponents-test.js index ebe7a9c9314da..41cac1683545b 100644 --- a/packages/relay-test-utils/__tests__/RelayMockEnvironmentWithComponents-test.js +++ b/packages/relay-test-utils/__tests__/RelayMockEnvironmentWithComponents-test.js @@ -65,8 +65,10 @@ describe('ReactRelayTestMocker with Containers', () => { if (props) { return `My id ${props.user.id} and name is ${props.user.name}`; } else if (error) { + // $FlowFixMe[incompatible-type] return
{error.message}
; } + // $FlowFixMe[incompatible-type] return
Loading...
; }} /> @@ -176,6 +178,7 @@ describe('ReactRelayTestMocker with Containers', () => { id name ...RelayMockEnvironmentWithComponentsTestProminentSolutionFragment + @dangerously_unaliased_fixme } } `; @@ -194,6 +197,7 @@ describe('ReactRelayTestMocker with Containers', () => { // to get flow to accept this typing. (props: $FlowFixMe) => { return ( + // $FlowFixMe[incompatible-type] { id name ...RelayMockEnvironmentWithComponentsTestRobustAwesomenessFragment + @dangerously_unaliased_fixme } } `; @@ -309,6 +314,7 @@ describe('ReactRelayTestMocker with Containers', () => { const [isLoading, setIsLoading] = useState(props.relay.isLoading()); return ( <> + {/* $FlowFixMe[incompatible-type] */}
    {props.user.friends.edges.map(({node, cursor}) => { return ( @@ -319,7 +325,11 @@ describe('ReactRelayTestMocker with Containers', () => { ); })}
- {isLoading &&
Loading more...
} + { + // $FlowFixMe[incompatible-type] + isLoading &&
Loading more...
+ } + {/* $FlowFixMe[incompatible-type] */}
); } else if (error) { + // $FlowFixMe[incompatible-type] return
{error.message}
; } + // $FlowFixMe[incompatible-type] return
Loading...
; }} /> @@ -546,6 +558,7 @@ describe('ReactRelayTestMocker with Containers', () => { ) @relay_test_operation { node(id: $id) { ...RelayMockEnvironmentWithComponentsTestUsefulAwesomenessFragment + @dangerously_unaliased_fixme } } `; @@ -561,9 +574,14 @@ describe('ReactRelayTestMocker with Containers', () => { const [isLoading, setIsLoading] = useState(false); return ( <> + {/* $FlowFixMe[incompatible-type] */}
{props.page.name}
Websites: {props.page.websites}
- {isLoading &&
Refetching...
} + { + // $FlowFixMe[incompatible-type] + isLoading &&
Refetching...
+ } + {/* $FlowFixMe[incompatible-type] */}
- - ); -} -``` -* Note that calling `loadNext` will use the original `order_by` and `search_term` values used for the initial query. During pagination, these value won't (*and shouldn't*) change. - -If we want to refetch the connection with *different* variables, we can use the `refetch` function provided by `usePaginationFragment`, similarly to how we do so when [Refetching Fragments with Different Data](../../refetching/refetching-fragments-with-different-data/): - - - - - - - -```js -/** - * FriendsListComponent.react.js - */ -import type {FriendsListComponent_user$key} from 'FriendsListComponent_user.graphql'; - -const React = require('React'); -const {useState, useEffect} = require('React'); - -const {graphql, usePaginationFragment} = require('react-relay'); - - -type Props = { - searchTerm?: string, - user: FriendsListComponent_user$key, -}; - -function FriendsListComponent(props: Props) { - const searchTerm = props.searchTerm; - const {data, loadNext, refetch} = usePaginationFragment( - graphql` - fragment FriendsListComponent_user on User { - name - friends( - order_by: $orderBy, - search_term: $searchTerm, - after: $cursor, - first: $count, - ) @connection(key: "FriendsListComponent_user_friends_connection") { - edges { - node { - name - age - } - } - } - } - `, - props.user, - ); - - useEffect(() => { - // When the searchTerm provided via props changes, refetch the connection - // with the new searchTerm - refetch({first: 10, search_term: searchTerm}, {fetchPolicy: 'store-or-network'}); - }, [searchTerm]) - - return ( - <> -

Friends of {data.name}:

- - {/* When the button is clicked, refetch the connection but sorted differently */} - - - ... - - - ); -} -``` - -Let's distill what's going on here: - -* Calling `refetch` and passing a new set of variables will fetch the fragment again *with the newly provided variables*. The variables you need to provide are a subset of the variables that the generated query expects; the generated query will require an `id`, if the type of the fragment has an `id` field, and any other variables that are transitively referenced in your fragment. - * In our case, we need to pass the count we want to fetch as the `first` variable, and we can pass different values for our filters, like `orderBy` or `searchTerm`. -* This will re-render your component and may cause it to suspend (as explained in [Loading States with Suspense](../../rendering/loading-states/)) if it needs to send and wait for a network request. If `refetch` causes the component to suspend, you'll need to make sure that there's a `Suspense` boundary wrapping this component from above. -* Conceptually, when we call refetch, we're fetching the connection *from scratch*. It other words, we're fetching it again from the *beginning* and *"resetting"* our pagination state. For example, if we fetch the connection with a different `search_term`, our pagination information for the previous `search_term` no longer makes sense, since we're essentially paginating over a new list of items. - -
- - - - - diff --git a/website/docs/guided-tour/refetching/introduction.md b/website/docs/guided-tour/refetching/introduction.md deleted file mode 100644 index 08c2e1948b5ea..0000000000000 --- a/website/docs/guided-tour/refetching/introduction.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -id: introduction -title: Introduction -slug: /guided-tour/refetching/ -description: Relay guide to refetching -keywords: -- refetching ---- - -import DocsRating from '@site/src/core/DocsRating'; -import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; - -After an app has been initially rendered, there are various scenarios in which you might want to refetch and show *new* or *different* data (e.g. change the currently displayed item), or maybe refresh the currently rendered data with the latest version from the server (e.g. refreshing a count), usually as a result of an event or user interaction. - -In this section we'll cover some of the most common scenarios and how to build them with Relay. - - diff --git a/website/docs/guided-tour/refetching/refetching-fragments-with-different-data.md b/website/docs/guided-tour/refetching/refetching-fragments-with-different-data.md deleted file mode 100644 index 81e954561a270..0000000000000 --- a/website/docs/guided-tour/refetching/refetching-fragments-with-different-data.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -id: refetching-fragments-with-different-data -title: Refetching Fragments with Different Data -slug: /guided-tour/refetching/refetching-fragments-with-different-data/ -description: Relay guide to refetching fragments with different data -keywords: -- refetching -- fragment ---- - -import DocsRating from '@site/src/core/DocsRating'; -import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; -import FbRefetchingFragments from './fb/FbRefetchingFragments.md'; -import FbAvoidSuspenseCaution from './fb/FbAvoidSuspenseCaution.md'; -import OssAvoidSuspenseNote from './OssAvoidSuspenseNote.md'; - -When referring to **"refetching a fragment"**, we mean fetching a *different* version of the data than the one was originally rendered by the fragment. For example, this might be to change a currently selected item, to render a different list of items than the one being shown, or more generally to transition the currently rendered content to show new or different content. - -Conceptually, this means fetching and rendering the currently rendered fragment again, but under a new query with *different variables*; or in other words, rendering the fragment under a new query root. Remember that *fragments can't be fetched by themselves: they need to be part of a query,* so we can't just "fetch" the fragment again by itself. - -## Using `useRefetchableFragment` - -To do so, we can also use the [`useRefetchableFragment`](../../../api-reference/use-refetchable-fragment/) Hook in combination with the `@refetchable` directive, which will automatically generate a query to refetch the fragment under, and which we can fetch using the `refetch` function: - - - - - - - -```js -import type {CommentBody_comment$key} from 'CommentBody_comment.graphql'; - -type Props = { - comment: CommentBody_comment$key, -}; - -function CommentBody(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment CommentBody_comment on Comment - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "CommentBodyRefetchQuery") { - body(lang: $lang) { - text - } - } - `, - props.comment, - ); - - const refetchTranslation = () => { - // We call refetch with new variables, - // which will refetch the @refetchable query with the - // new variables and update this component with the - // latest fetched data. - refetch({lang: 'SPANISH'}); - }; - - return ( - <> -

{data.body?.text}

- - - ); -} -``` - -Let's distill what's happening in this example: - -* `useRefetchableFragment` behaves similarly to [`useFragment`](../../../api-reference/use-fragment/) (see the [Fragments](../../rendering/fragments/) section), but with a few additions: - * It expects a fragment that is annotated with the `@refetchable` directive. Note that `@refetchable` directive can only be added to fragments that are "refetchable", that is, on fragments that are on `Viewer`, on `Query`, on any type that implements `Node` (i.e. a type that has an `id` field), or on a [`@fetchable`](https://fb.workplace.com/groups/graphql.fyi/permalink/1539541276187011/) type. -* It returns a `refetch` function, which is already Flow-typed to expect the query variables that the generated query expects. -* It takes two Flow type parameters: the type of the generated query (in our case `CommentBodyRefetchQuery`), and a second type which can always be inferred, so you only need to pass underscore (`_`). -* We're calling the `refetch` function with 2 main inputs: - * The first argument is the set of variables to fetch the fragment with. In this case, calling `refetch` and passing a new set of variables will fetch the fragment again *with the newly provided variables*. The variables you need to provide are a subset of the variables that the `@refetchable` query expects; the query will require an `id`, if the type of the fragment has an `id` field, and any other variables that are transitively referenced in your fragment. - * In this case we're passing the current comment `id` and a new value for the `translationType` variable to fetch the translated comment body. - * We are not passing a second options argument in this case, which means that we will use the default `fetchPolicy` of `'store-or-network'`, which will skip the network request if the new data for that fragment is already cached (as we covered in [Reusing Cached Data For Render](../../reusing-cached-data/)). -* Calling `refetch` will re-render the component and may cause `useRefetchableFragment` to suspend (as explained in [Loading States with Suspense](../../rendering/loading-states/)). This means that you'll need to make sure that there's a `Suspense` boundary wrapping this component from above in order to show a fallback loading state. - -
- -:::info -Note that this same behavior also applies to using the `refetch` function from [`usePaginationFragment`](../../../api-reference/use-pagination-fragment). -::: - -### If you need to avoid Suspense - -In some cases, you might want to avoid showing a Suspense fallback, which would hide the already rendered content. For these cases, you can use [`fetchQuery`](../../../api-reference/fetch-query/) instead, and manually keep track of a loading state: - - - - - - - - - -```js -import type {CommentBody_comment$key} from 'CommentBody_comment.graphql'; - -type Props = { - comment: CommentBody_comment$key, -}; - -function CommentBody(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment CommentBody_comment on Comment - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "CommentBodyRefetchQuery") { - body(lang: $lang) { - text - } - } - `, - props.comment, - ); - - const [isRefetching, setIsRefreshing] = useState(false) - const refetchTranslation = () => { - if (isRefetching) { return; } - setIsRefreshing(true); - - // fetchQuery will fetch the query and write - // the data to the Relay store. This will ensure - // that when we re-render, the data is already - // cached and we don't suspend - fetchQuery(environment, AppQuery, variables) - .subscribe({ - complete: () => { - setIsRefreshing(false); - - // *After* the query has been fetched, we call - // refetch again to re-render with the updated data. - // At this point the data for the query should - // be cached, so we use the 'store-only' - // fetchPolicy to avoid suspending. - refetch({lang: 'SPANISH'}, {fetchPolicy: 'store-only'}); - } - error: () => { - setIsRefreshing(false); - } - }); - }; - - return ( - <> -

{data.body?.text}

- - - ); -} -``` - -Let's distill what's going on here: - -* When refetching, we now keep track of our own `isRefetching` loading state, since we are avoiding suspending. We can use this state to render a busy spinner or similar loading UI in our component, *without* hiding the content. -* In the event handler, we first call `fetchQuery`, which will fetch the query and write the data to the local Relay store. When the `fetchQuery` network request completes, we call `refetch` so that we render the updated data, similar to the previous example. -* At this point, when `refetch` is called, the data for the fragment should already be cached in the local Relay store, so we use `fetchPolicy` of `'store-only'` to avoid suspending and only read the already cached data. - - diff --git a/website/docs/guided-tour/refetching/refetching-queries-with-different-data.md b/website/docs/guided-tour/refetching/refetching-queries-with-different-data.md index 6640c5a9c101c..af6a18239fabc 100644 --- a/website/docs/guided-tour/refetching/refetching-queries-with-different-data.md +++ b/website/docs/guided-tour/refetching/refetching-queries-with-different-data.md @@ -130,6 +130,7 @@ function App(props: Props) { const refetch = useCallback(() => { if (isRefetching) { return; } setIsRefetching(true); + const variables = { id: 'different-id' }; // fetchQuery will fetch the query and write // the data to the Relay store. This will ensure @@ -146,7 +147,7 @@ function App(props: Props) { // At this point the data for the query should // be cached, so we use the 'store-only' // fetchPolicy to avoid suspending. - loadQuery({id: 'different-id'}, {fetchPolicy: 'store-only'}); + loadQuery(variables, {fetchPolicy: 'store-only'}); }, error: () => { setIsRefetching(false); @@ -292,6 +293,7 @@ function App(props: Props) { const refetch = useCallback(() => { if (isRefreshing) { return; } setIsRefreshing(true); + const variables = { id: 'different-id' }; // fetchQuery will fetch the query and write // the data to the Relay store. This will ensure @@ -313,7 +315,7 @@ function App(props: Props) { fetchKey: (prev?.options.fetchKey ?? 0) + 1, fetchPolicy: 'store-only', }, - variables: {id: 'different-id'} + variables, })); }, error: () => { diff --git a/website/docs/guided-tour/refetching/refreshing-fragments.md b/website/docs/guided-tour/refetching/refreshing-fragments.md deleted file mode 100644 index 937af7feb3495..0000000000000 --- a/website/docs/guided-tour/refetching/refreshing-fragments.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -id: refreshing-fragments -title: Refreshing Fragments -slug: /guided-tour/refetching/refreshing-fragments/ -description: Relay guide to refreshing fragments -keywords: -- refreshing -- fragment ---- - -import DocsRating from '@site/src/core/DocsRating'; -import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; -import FbRefreshingUsingRealTimeFeatures from './fb/FbRefreshingUsingRealTimeFeatures.md'; -import FbRefreshingFragments from './fb/FbRefreshingFragments.md'; -import FbAvoidSuspenseCaution from './fb/FbAvoidSuspenseCaution.md'; -import OssAvoidSuspenseNote from './OssAvoidSuspenseNote.md'; - -When referring to **"refreshing a fragment"**, we mean fetching the *exact* same data that was originally rendered by the fragment, in order to get the most up-to-date version of that data from the server. - -## Using real-time features - - - - - - -If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. - -One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). - - -## Using `useRefetchableFragment` - -In order to manually refresh the data for a fragment, we need a query to refetch the fragment under; remember, *fragments can't be fetched by themselves: they need to be part of a query,* so we can't just "fetch" the fragment again by itself. - -To do so, we can also use the [`useRefetchableFragment`](../../../api-reference/use-refetchable-fragment/) Hook in combination with the `@refetchable` directive, which will automatically generate a query to refetch the fragment under, and which we can fetch using the `refetch` function: - - - - - - - -```js -import type {UserComponent_user$key} from 'UserComponent_user.graphql'; - -type Props = { - user: UserComponent_user$key, -}; - -function UserComponent(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment UserComponent_user on User - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "UserComponentRefreshQuery") { - id - name - friends { - count - } - } - `, - props.user, - ); - - const refresh = useCallback(() => { - // We call refetch with empty variables: `{}`, - // which will refetch the @refetchable query with the same - // original variables the fragment was fetched with, and update - // this component with the latest fetched data. - // The fetchPolicy ensures we always fetch from the server and skip - // the local data cache. - refetch({}, {fetchPolicy: 'network-only'}) - }), [/* ... */]; - - return ( - <> -

{data.name}

-
Friends count: {data.friends?.count}
- - - ); -} -``` - -Let's distill what's happening in this example: - -* `useRefetchableFragment` behaves similarly to [`useFragment`](../../../api-reference/use-fragment/) (see the [Fragments](../../rendering/fragments/) section), but with a few additions: - * It expects a fragment that is annotated with the `@refetchable` directive. Note that `@refetchable` directive can only be added to fragments that are "refetchable", that is, on fragments that are on `Viewer`, on `Query`, on any type that implements `Node` (i.e. a type that has an `id` field). -* It returns a `refetch` function, which is already Flow-typed to expect the query variables that the generated query expects -* It takes two Flow type parameters: the type of the generated query (in our case `UserComponentRefreshQuery`), and a second type which can always be inferred, so you only need to pass underscore (`_`). -* We're calling the `refetch` function with 2 main inputs: - * The first argument is the set of variables to fetch the fragment with. In this case, calling `refetch` and passing an empty set of variables will fetch the fragment again *with the exact same variables the fragment was originally fetched with,* which is what we want for a refresh. - * In the second argument we are passing a `fetchPolicy` of `'network-only'` to ensure that we always fetch from the network and skip the local data cache. -* Calling `refetch` will re-render the component and cause `useRefetchableFragment` to suspend (as explained in [Loading States with Suspense](../../rendering/loading-states/)), since a network request will be required due to the `fetchPolicy` we are using. This means that you'll need to make sure that there's a `Suspense` boundary wrapping this component from above in order to show a fallback loading state. - -
- -:::info -Note that this same behavior also applies to using the `refetch` function from [`usePaginationFragment`](../../../api-reference/use-pagination-fragment). -::: - -### If you need to avoid Suspense - -In some cases, you might want to avoid showing a Suspense fallback, which would hide the already rendered content. For these cases, you can use [`fetchQuery`](../../../api-reference/fetch-query/) instead, and manually keep track of a loading state: - - - - - - - - - -```js -import type {UserComponent_user$key} from 'UserComponent_user.graphql'; - -type Props = { - user: UserComponent_user$key, -}; - -function UserComponent(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment UserComponent_user on User - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "UserComponentRefreshQuery") { - id - name - friends { - count - } - } - `, - props.user, - ); - - const [isRefreshing, setIsRefreshing] = useState(false); - const refresh = useCallback(() => { - if (isRefreshing) { return; } - setIsRefreshing(true); - - // fetchQuery will fetch the query and write - // the data to the Relay store. This will ensure - // that when we re-render, the data is already - // cached and we don't suspend - fetchQuery(environment, AppQuery, variables) - .subscribe({ - complete: () => { - setIsRefreshing(false); - - // *After* the query has been fetched, we call - // refetch again to re-render with the updated data. - // At this point the data for the query should - // be cached, so we use the 'store-only' - // fetchPolicy to avoid suspending. - refetch({}, {fetchPolicy: 'store-only'}); - }, - error: () => { - setIsRefreshing(false); - } - }); - }, [/* ... */]); - - return ( - <> -

{data.name}

-
Friends count: {data.friends?.count}
- - - ); -} -``` - -Let's distill what's going on here: - -* When refreshing, we now keep track of our own `isRefreshing` loading state, since we are avoiding suspending. We can use this state to render a busy spinner or similar loading UI in our component, *without* hiding the content. -* In the event handler, we first call `fetchQuery`, which will fetch the query and write the data to the local Relay store. When the `fetchQuery` network request completes, we call `refetch` so that we render the updated data, similar to the previous example. -* At this point, when `refetch` is called, the data for the fragment should already be cached in the local Relay store, so we use `fetchPolicy` of `'store-only'` to avoid suspending and only read the already cached data. - - diff --git a/website/docs/guided-tour/refetching/refreshing-queries.md b/website/docs/guided-tour/refetching/refreshing-queries.md index 41af90583486d..98bb479c046df 100644 --- a/website/docs/guided-tour/refetching/refreshing-queries.md +++ b/website/docs/guided-tour/refetching/refreshing-queries.md @@ -25,9 +25,11 @@ When referring to **"refreshing a query"**, we mean fetching the *exact* same da + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## When using `useQueryLoader` / `loadQuery` diff --git a/website/docs/guided-tour/rendering/loading-states.md b/website/docs/guided-tour/rendering/loading-states.md index 0c52b41bd5781..35d92e3c48634 100644 --- a/website/docs/guided-tour/rendering/loading-states.md +++ b/website/docs/guided-tour/rendering/loading-states.md @@ -252,6 +252,6 @@ Fragments are also integrated with Suspense in order to support rendering of dat -Additionally, our APIs for refetching ([Refreshing and Refetching](../../refetching/)) and for [rendering connections](../../list-data/connections/) are also integrated with Suspense; for these use cases, these APIs will also suspend. +Additionally, our APIs for fetching ([Refreshing and Refetching](../list-data/introduction.md)) and for [rendering connections](../../list-data/connections/) are also integrated with Suspense; for these use cases, these APIs will also suspend. diff --git a/website/docs/guided-tour/reusing-cached-data/fetch-policies.md b/website/docs/guided-tour/reusing-cached-data/fetch-policies.md index cf5a31a4c22f6..08e9ab115a738 100644 --- a/website/docs/guided-tour/reusing-cached-data/fetch-policies.md +++ b/website/docs/guided-tour/reusing-cached-data/fetch-policies.md @@ -50,7 +50,7 @@ Specifically, `fetchPolicy` can be any of the following options: ** * "store-only": *will* *only* reuse locally cached data, and will *never* send a network request to fetch the query. In this case, the responsibility of fetching the query falls to the caller, but this policy could also be used to read and operate on data that is entirely [local](../../updating-data/local-data-updates/). -Note that the `refetch` function discussed in the [Fetching and Rendering Different Data](../../refetching/) section also takes a `fetchPolicy`. +Note that the `refetch` function discussed in the [Fetching and Rendering Different Data](../list-data/introduction.md) section also takes a `fetchPolicy`. diff --git a/website/docs/guided-tour/updating-data/introduction.md b/website/docs/guided-tour/updating-data/introduction.md index 50e732fc8134f..c2b1afc22c08a 100644 --- a/website/docs/guided-tour/updating-data/introduction.md +++ b/website/docs/guided-tour/updating-data/introduction.md @@ -1,21 +1,22 @@ --- id: introduction title: Introduction -slug: /guided-tour/updating-data/ +slug: /guided-tour/updating-data/introduction description: Relay guide to updating data keywords: - updating - mutation - useMutation - commitMutation +- relay store --- import DocsRating from '@site/src/core/DocsRating'; import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; -In previous sections, the guided tour discussed how to fetch data using GraphQL queries. Though [refetching data](../refetching/) can have the *incidental* effect of modifying data in Relay's local store (if the refetched data has changed), we haven't discussed any ways to *intentionally* modify our locally stored data. +In the [fetching data](../list-data/introduction.md) section, we discuss how to fetch data using GraphQL queries. Though fetching data can have the *incidental* effect of modifying data in Relay's local store (if the fetched data has changed), we haven't discussed any ways to *intentionally* modify our locally stored data. -This section will do just that: it will discuss how to update data on the server and how to update our local data store. +This section will do just that: it will discuss how to update our local data store, and data on the server. :::note The **Relay store** is a cache of GraphQL data, associated with a given Relay environment, that we have encountered during the execution of an application. diff --git a/website/docs/guided-tour/updating-data/typesafe-updaters-faq.md b/website/docs/guided-tour/updating-data/typesafe-updaters-faq.md index 22a2f46ca770f..3bc6a5c393460 100644 --- a/website/docs/guided-tour/updating-data/typesafe-updaters-faq.md +++ b/website/docs/guided-tour/updating-data/typesafe-updaters-faq.md @@ -32,6 +32,8 @@ Is something missing from this Q&A? Are you confused? Would you like help adopti Typesafe updaters is the name given to a project to provide a typesafe and ergonomic alternative to the existing APIs for imperatively updating data in the Relay store. +For example, [`readUpdatableFragment`](../../../api-reference/store/#readupdatablefragmentfragment-updatablefragmenttfragmenttype-tdatafragmentreference-hasupdatablespreadtfragmenttype-updatabledatatdata) and [`readUpdatableQuery`](../../../api-reference/store/#readupdatablequeryquery-updatablequerytvariables-tdatavariables-tvariables-updatabledatatdata) are two typesafe updaters that the store exposes. + ## Why? Relay provides typesafe and ergonomic APIs for fetching and managing data that originates on the server. In addition, Relay provides the ability to define local-only fields in **client schema extensions**. However, the APIs for mutating the data in these fields has hitherto been verbose and not ergonomic, meaning that we could not recommend Relay as a solution for managing local state. @@ -40,16 +42,12 @@ Relay provides typesafe and ergonomic APIs for fetching and managing data that o The pre-existing APIs are verbose and not typesafe. They make it easy to make a variety of mistakes and require that the developer understand a new set of APIs only when writing updaters. -Typesafe updaters is a set of APIs that are typesafe and (hopefully) more ergonomic. They leverage well-known Relay idioms (queries, fragments, type refinement) and use getters and setters instead of requiring that the developer learn about a set of methods that are unused elsewhere. +Typesafe updaters is a set of APIs that are typesafe and more ergonomic. They leverage well-known Relay idioms (queries, fragments, type refinement) and use getters and setters instead of requiring that the developer learn about a set of methods that are unused elsewhere. ## How does a developer use typesafe updaters? With typesafe updaters, a developers writes an updatable query or a fragment that specifies the data to imperatively update. Then, the developer reads out that data from the store, returning a so-called **updatable proxy**. Then, the developer mutates that updatable proxy. Mutating that updatable proxy using setters (e.g. `updatableData.name = "Godzilla"`) results in calls to the old API, but with added type safety. -## Why are these labeled `_EXPERIMENTAL`? - -These are de facto not experimental. We encourage you to use them when writing new code! This suffix will be removed soon. - ## What is an updatable query or fragment? An updatable query or fragment is a query or fragment that has the `@updatable` directive. @@ -77,7 +75,7 @@ You should select that field in both a regular query/fragment **and** in an upda ## Where do I get a `store`? -The classes `RelayRecordSourceSelectorProxy` and `RelayRecordSourceProxy` contain the methods `readUpdatableQuery` and `readUpdatableFragment`. One can acquire an instance of these classes: +The classes `RelayRecordSourceSelectorProxy`, `RecordSourceProxy` and `RelayRecordSourceProxy` contain the methods `readUpdatableQuery` and `readUpdatableFragment`. One can acquire an instance of these classes: * In updaters of mutations and subscriptions * In optimistic updaters of mutations diff --git a/website/docs/guided-tour/list-data/updating-connections.md b/website/docs/guided-tour/updating-data/updating-connections.md similarity index 97% rename from website/docs/guided-tour/list-data/updating-connections.md rename to website/docs/guided-tour/updating-data/updating-connections.md index f0430022586bb..f864bba17d973 100644 --- a/website/docs/guided-tour/list-data/updating-connections.md +++ b/website/docs/guided-tour/updating-data/updating-connections.md @@ -15,7 +15,7 @@ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/interna Usually when you're rendering a connection, you'll also want to be able to add or remove items to/from the connection in response to user actions. -As explained in our [Updating Data](../../updating-data/) section, Relay holds a local in-memory store of normalized GraphQL data, where records are stored by their IDs. When creating mutations, subscriptions, or local data updates with Relay, you must provide an [`updater`](../../updating-data/graphql-mutations/#updater-functions) function, inside which you can access and read records, as well as write and make updates to them. When records are updated, any components affected by the updated data will be notified and re-rendered. +Relay holds a local in-memory store of normalized GraphQL data, where records are stored by their IDs. When creating mutations, subscriptions, or local data updates with Relay, you must provide an [`updater`](../../updating-data/graphql-mutations/#updater-functions) function, inside which you can access and read records, as well as write and make updates to them. When records are updated, any components affected by the updated data will be notified and re-rendered. ## Connection Records diff --git a/website/docs/guides/client-schema-extensions.md b/website/docs/guides/client-schema-extensions.md index a9a0959e0d49c..ef9c7c4272e5c 100644 --- a/website/docs/guides/client-schema-extensions.md +++ b/website/docs/guides/client-schema-extensions.md @@ -29,9 +29,10 @@ The Relay Compiler fully supports client-side extensions of the schema, which al ## Extending the server schema -To extend the server schema, create a new `.graphql` file inside your `--src` directory. -Let's call it `./src/clientSchema.graphql`. -This file needs to be in a folder referenced in the `"schemaExtensions"` of your Relay config. +To extend the server schema, create a new `.graphql` file inside your `--src` +directory. Let's call it `./src/clientSchema.graphql`. This file needs to be +referenced in the `"schemaExtensions"` of your Relay config, either directly or +via its folder. This schema describes what local data can be queried on the client. It can even be used to extend an existing server schema. diff --git a/website/docs/guides/data-driven-dependencies/client-3d.md b/website/docs/guides/data-driven-dependencies/client-3d.md index 5f4d35eae23e9..0369e9b459a78 100644 --- a/website/docs/guides/data-driven-dependencies/client-3d.md +++ b/website/docs/guides/data-driven-dependencies/client-3d.md @@ -184,6 +184,10 @@ in this example, these separate fragments are `FOO_FRAGMENT`, `BAR_FRAGMENT`, an to this fragment's data as an argument. 3. Return the final component using Relay's `MatchContainer`, providing the returned query data as a prop. +Notice that in Client 3D, just as in Server 3D, you cannot use `@module` on multiple fragments on the SAME concrete type (but they can be on the same abstract type i.e. a union or an interface). + +So in this example, `Client3DFooComponent_Fragment` is on the concrete type `Client3DFoo`, and `Client3DBarComponent_Fragment` is on the concrete type `Client3DBar`. If `Client3DBarComponent_Fragment` was also on `Client3DFoo`, the relay compiler would report an error. However, all three concrete types implement the same parent interface `IClient3D`, which is fine. + > **NOTE:** If you are in www, but not in Comet, you should use `RelayFBMatchContainer` instead of `MatchContainer`. diff --git a/website/docs/guides/data-driven-dependencies/server-3d.md b/website/docs/guides/data-driven-dependencies/server-3d.md index e0fa8e51ada8f..4b013110daf1d 100644 --- a/website/docs/guides/data-driven-dependencies/server-3d.md +++ b/website/docs/guides/data-driven-dependencies/server-3d.md @@ -276,6 +276,8 @@ public function commentContentRenderer(Traversable $supported): Awaitabl Your Relay fragment can now use `@match` to specify that for the `comment_content_renderer` field, we expect dependencies to be decided by the data. In this example, if the `comment_content_renderer` field is of type `CommentMarkdownRenderer`, we load the `CommentMarkdownRenderer.react` component and use the `CommentMarkdownRenderer_comment` fragment to load its data. Similar for the plaintext variant. +> **NOTE:** The inline fragments annotated with `@module` on the same parent 3D fragment must be on distinct concrete types. If they are on the same concrete type, the relay compiler will report an error. So in the example below, `CommentMarkdownRenderer_comment` must be on a different concrete type than `CommentPlaintextRenderer_comment` (for example, the former could be on a `MarkdownComment` type, and the latter on a `PlaintextComment` type. Both could implement a parent interface `Comment`). + On the Relay side you'd write: ```graphql diff --git a/website/docs/guides/relay-resolvers/defining-fields.md b/website/docs/guides/relay-resolvers/defining-fields.md index 58d6d66e55954..a384138e1f102 100644 --- a/website/docs/guides/relay-resolvers/defining-fields.md +++ b/website/docs/guides/relay-resolvers/defining-fields.md @@ -110,3 +110,42 @@ This is just a simple resolver that reads from the model type and returns a scal * [Field Arguments](./field-arguments.md) * [Live Fields](./live-fields.md) * [Derived Fields](./derived-fields.md) + + + +## Simplified Syntax for Property Lookups + +If you have a ["weak" type](./defining-types.md#defining-a-weak-type), you can easily define a simple resolver that just returns a property from the underlying model. For example, take a resolver being defined on the `UserModel` that looks like: +```tsx +/** + * @RelayResolver + */ +export function name(user: UserModel): string { + return user.name; +} +``` + +When defining the weak type, this resolver can by automatically generated by using a docblock with `@gqlField` over the field you want to expose. +```tsx +/** + * @RelayResolver + */ +export type UserModel = { + /** + * @gqlField + */ + name: string, +} +``` + +You can optionally include a description or `@deprecated` tag in the docblock +```tsx +/** + * @gqlField + * @deprecated Do not use this field anymore + * + * This is a description. Include more information + * about your field here. + */ +``` + diff --git a/website/docs/guides/relay-resolvers/defining-types.md b/website/docs/guides/relay-resolvers/defining-types.md index 128e3183739a3..66471ade373ca 100644 --- a/website/docs/guides/relay-resolvers/defining-types.md +++ b/website/docs/guides/relay-resolvers/defining-types.md @@ -125,7 +125,9 @@ interface IUser { You could define two (or more) concrete resolver types that implement the IUser interface by adding annotations in the docblock (the same applies for unions). + Note, support for abstract types is not available for relay resolvers in Flow syntax (yet). + `. The codemod doesn't support all cases, so you might need to modify some files manually after it runs. + diff --git a/website/docs/guides/relay-resolvers/return-types.md b/website/docs/guides/relay-resolvers/return-types.md index 9f4e1bb070504..d3a48b89b9907 100644 --- a/website/docs/guides/relay-resolvers/return-types.md +++ b/website/docs/guides/relay-resolvers/return-types.md @@ -109,6 +109,38 @@ function Post() { } ``` +## Abstract Types + +Resolvers may return some permutations of "abstract" types (GraphQL unions and interfaces). To use this feature simply use the abstract type's name in the docblock field description and include the typename in the object returned from your resolver. For "strong" types, that will look like: `{id: DataID, __typename: string}`. For "weak" types that will look like: `{__relay_model_instance: T, __typename: string}`. + +```tsx +import {DataID} from 'relay-runtime'; + +type AnimalTypenames = "Cat" | "Dog"; +/** + * @RelayResolver User.pet: Animal + */ +export function pet(user: User): {id: DataID, __typename: AnimalTypenames } { + return {id: "5", __typename: "Dog" } +} +``` + +:::tip +Relay will generate type assertions to ensure your resolver function returns the expected type. However, not all combinations are supported. For example, Relay does not yet support the following permutations of abstract types: Unions including weak types, abstract types which mix strong add weak types, and abstract types which include server-backed types. +::: + +While abstract types themselves cannot be defined using Resolver syntax today, you may define interfaces and unions, as well as their members, using [Client Schema Extensions](../client-schema-extensions.md). For example: + +```graphql title="client-schema.graphql" +interface Animal { + legs: Int +} + +extend type Cat implements Animal { + __do_not_use: String # Placeholder because GraphQL does not allow empty field sets. +} +``` + ## JavaScript Values There are rare cases where you want to return an arbitrary JavaScript value from your Resolver schema, one which cannot not have a corresponding GraphQL type. As an escape hatch Relay supports a custom return type `RelayResolverValue` that allows you to return any JavaScript value from your resolver. **JavaScript values returned from resolvers should be immutable.** diff --git a/website/docs/guides/required-directive.md b/website/docs/guides/required-directive.md index 470d7a5db2fd1..65debdfac2b06 100644 --- a/website/docs/guides/required-directive.md +++ b/website/docs/guides/required-directive.md @@ -180,7 +180,9 @@ fragment MyFrag on Actor { In this situation Relay will generate a union type like: `{__typename: 'User', name: string} | {__typename: '%ignore this%}`. Now you can check the `__typename` field to narrow your object's type down to one that has a non-nullable `name`. + Example diff showing the adoption of this strategy: D24370183 + ### Why not implement this at the schema/server level? @@ -197,6 +199,7 @@ Basically every value returned by Relay is nullable. This is intentional since w _Extracted from [this comment thread](https://fb.workplace.com/groups/cometeng/permalink/937671436726844/?comment_id=937681186725869)._ _Further discussion in [this comment thread](https://fb.workplace.com/groups/cometeng/permalink/937671436726844/?comment_id=938335873327067)._ + ### Can `(action: NONE)` be the default? diff --git a/website/docs/guides/testing-relay-components.md b/website/docs/guides/testing-relay-components.md index ea4de6f2cc36e..88f444adfa076 100644 --- a/website/docs/guides/testing-relay-components.md +++ b/website/docs/guides/testing-relay-components.md @@ -57,7 +57,9 @@ With the `MockPayloadGenerator` and `@relay_test_operation`, we want to get rid **[React Testing Library](https://testing-library.com/react)** is a set of helpers that let you test React components without relying on their implementation details. This approach makes refactoring a breeze and also nudges you towards best practices for accessibility. Although it doesn't provide a way to "shallowly" render a component without its children, a test runner like Jest lets you do this by [mocking](https://reactjs.org/docs/testing-recipes.html#mocking-modules). + Note: The [`ReactTestRenderer`](https://www.npmjs.com/package/react-test-renderer) library has been deprecated since React v18. `ReactTestRenderer` may still be referenced internally as an alternative to React Testing Library. However, when possible, we recommend using React Testing Library (or `@testing-library/react-native`) to test your React applications with Relay. + ## RelayMockEnvironment API Overview diff --git a/website/docs/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md b/website/docs/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md index fc9d1dc248aea..a8627c0b15333 100644 --- a/website/docs/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md +++ b/website/docs/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md @@ -17,7 +17,7 @@ import DocsRating from '@site/src/core/DocsRating'; ## Compatibility between Relay Hooks and Containers -Relay Hooks are fully compatible with Relay's [container-based APIs](../../api-reference/legacy-apis/), meaning that containers can render components that use Hooks, and vice-versa. +Relay Hooks are fully compatible with Relay's container-based APIs, meaning that containers can render components that use Hooks, and vice-versa. This means that you can adopt Relay Hooks incrementally, either by using them exclusively for new code, or by migrating specific parts of your app, without affecting the rest of your existing application. diff --git a/website/docs/tutorial/connections-pagination.md b/website/docs/tutorial/connections-pagination.md index 487a0bd869617..7c0097a24b721 100644 --- a/website/docs/tutorial/connections-pagination.md +++ b/website/docs/tutorial/connections-pagination.md @@ -243,21 +243,16 @@ const onLoadMore = () => loadNext(3); Run `npm run relay`. Now the Load More button should cause another three comments to be loaded. -### Improving the Loading Experience with useTransition +### Improving the Loading Experience As it stands, there’s no user feedback when you click the “Load More” button until the new comments have finished loading and then appear. Every user action should result in immediate feedback, so let’s show a spinner while the new data is loading — but without hiding the existing UI. -To do that, we need to wrap our call to `loadNext` inside a React transition. Here’s the change’s we need to make: +To do that, we need can use the `isLoadingNext` boolean value returned from `usePaginationFragment`. Here are the changes we need to make: ``` function StoryCommentsSection({story}) { // change-line - const [isPending, startTransition] = useTransition(); - const {data, loadNext} = usePaginationFragment(StoryCommentsSectionFragment, story); - // change - const onLoadMore = () => startTransition(() => { - loadNext(3); - }); + const {data, loadNext, isLoadingNext} = usePaginationFragment(StoryCommentsSectionFragment, story); // end-change return ( <> @@ -268,18 +263,16 @@ function StoryCommentsSection({story}) { )} // change-line - {isPending && } + {isLoadingNext && } ); } ``` -Every user action with results that aren’t immediate should be wrapped in a React transition. This allows React to prioritize different updates: for example, if when the data becomes available and React is rendering the new comments, the user clicks on another tab to navigate to a different page, React can interrupt rendering the comments in order to render the new page that the user wanted. - * * * ## Infinite Scrolling Newsfeed Stories diff --git a/website/docs/tutorial/refetchable-fragments.md b/website/docs/tutorial/refetchable-fragments.md index d907d620c5674..18d6f46c059ca 100644 --- a/website/docs/tutorial/refetchable-fragments.md +++ b/website/docs/tutorial/refetchable-fragments.md @@ -336,7 +336,9 @@ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/interna Besides fragments on types that implement `Node`, you can also refetch fragments that are on `Viewer` (since the viewer is assumed to be stable throughout a session) and that are at the top level of a query (since there’s no field above them that could change identity). + Meta only: Ents marked with GraphQLFetchable can also be refetched. + diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 5b21c208dc9d9..e85ded3c541da 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -126,12 +126,6 @@ module.exports = { pinned: true, description: 'Used at autoguru.com.au, and affiliates', }, - { - caption: 'Foton', - image: '/img/logos/foton.png', - infoLink: 'https://fotontech.io', - pinned: false, - }, { caption: 'M1 Finance', image: '/img/logos/m1finance.png', @@ -156,12 +150,6 @@ module.exports = { infoLink: 'http://www.habilelabs.io/', pinned: false, }, - { - caption: 'Quanto', - image: '/img/logos/quanto.png', - infoLink: 'https://www.contaquanto.com.br/', - pinned: false, - }, { caption: 'Butterfly Network', image: '/img/logos/butterfly.png', @@ -198,6 +186,18 @@ module.exports = { infoLink: 'https://www.rea-app.fr/', pinned: false, }, + { + caption: 'Steep Wellness', + image: '/img/logos/steep.png', + infoLink: 'https://steepapp.com', + pinned: false, + }, + { + caption: 'GigSmart', + image: '/img/logos/gigsmart.png', + infoLink: 'https://gigsmart.com', + pinned: false, + }, ], }, onBrokenLinks: 'throw', diff --git a/website/sidebars.js b/website/sidebars.js index f39bb6ffe2fb0..1d073dee1563b 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -19,6 +19,7 @@ const {fbContent} = require('docusaurus-plugin-internaldocs-fb/internal'); const Guides = { 'Fetching Data': [ + 'guided-tour/list-data/introduction', ...fbContent({ internal: [ { @@ -83,7 +84,9 @@ const Guides = { 'guides/semantic-nullability', ], 'Updating Data': [ - 'guided-tour/list-data/updating-connections', + 'guided-tour/updating-data/introduction', + 'guided-tour/updating-data/graphql-mutations', + 'guided-tour/updating-data/updating-connections', 'guided-tour/updating-data/imperatively-modifying-store-data', 'guided-tour/updating-data/imperatively-modifying-linked-fields', 'guided-tour/updating-data/typesafe-updaters-faq', @@ -216,6 +219,7 @@ module.exports = { 'api-reference/relay-runtime/request-subscription', 'api-reference/relay-runtime/observe-fragment', 'api-reference/relay-runtime/wait-for-fragment-data', + 'api-reference/relay-runtime/runtime-config', ], }, { @@ -225,7 +229,6 @@ module.exports = { ], }, 'api-reference/graphql/graphql-directives', - 'api-reference/legacy-apis/legacy-apis', ], 'Testing and Debugging': [ 'guides/testing-relay-components', @@ -235,6 +238,7 @@ module.exports = { 'debugging/fb/debugging-and-troubleshooting', 'debugging/relay-devtools', 'debugging/fb/network-logger', + 'debugging/fb/performance-logger', 'debugging/inconsistent-typename-error', 'debugging/declarative-mutation-directives', 'debugging/fb/debugging-suspense', diff --git a/website/src/pages/index.js b/website/src/pages/index.js index b73ec519e7a95..dea9936b67d91 100755 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -86,7 +86,6 @@ const HomeSplash = () => { const Index = () => { const {siteConfig} = useDocusaurusContext(); const {withBaseUrl} = useBaseUrlUtils(); - const {isDarkTheme} = useThemeConfig(); const showcase = siteConfig.customFields.users .filter(user => { @@ -94,7 +93,7 @@ const Index = () => { }) .map((user, i) => { return ( - +
{showcase}
-

Are you using this project?

- - Add your project - diff --git a/website/static/img/logos/foton.png b/website/static/img/logos/foton.png deleted file mode 100644 index 2eca0cec32bca..0000000000000 Binary files a/website/static/img/logos/foton.png and /dev/null differ diff --git a/website/static/img/logos/gigsmart.png b/website/static/img/logos/gigsmart.png new file mode 100644 index 0000000000000..88f70ee9dd8d4 Binary files /dev/null and b/website/static/img/logos/gigsmart.png differ diff --git a/website/static/img/logos/quanto.png b/website/static/img/logos/quanto.png deleted file mode 100644 index b58b1b69f5a84..0000000000000 Binary files a/website/static/img/logos/quanto.png and /dev/null differ diff --git a/website/static/img/logos/steep.png b/website/static/img/logos/steep.png new file mode 100644 index 0000000000000..ca4662023366b Binary files /dev/null and b/website/static/img/logos/steep.png differ diff --git a/website/versioned_docs/version-v13.0.0/glossary/glossary.md b/website/versioned_docs/version-v13.0.0/glossary/glossary.md index c0d23ed4ec388..726f76204f0e7 100644 --- a/website/versioned_docs/version-v13.0.0/glossary/glossary.md +++ b/website/versioned_docs/version-v13.0.0/glossary/glossary.md @@ -133,11 +133,15 @@ A directive which declares that a field implements the [connection](#connection) ## Connection + A field implementing the connection spec. See here for more details on the spec, and the section of the guided tour on rendering list data and pagination. + + A field implementing the connection spec. See the section of the guided tour on rendering list data and pagination. + See also [`usePaginationFragment`](../api-reference/use-pagination-fragment). @@ -357,7 +361,9 @@ A lightweight API for specifying a that a React component should be loaded on de This API is safe to use in entrypoint files. + See [the npm module](https://www.npmjs.com/package/jsresource). + ## Lazy Loading @@ -419,11 +425,15 @@ TODO A mutation is a combination of two things: a mutation on the backend, followed by query against updated data. + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations), and [this article](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/mutation-root-fields/) on defining mutations in your hack code. + + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations). + ## Mutation Root Query @@ -539,7 +549,9 @@ Required because of current limitations on dynamically loading components in Rea For Relay to process a file with a GraphQL literal, it must be included in a project. A project specifies the folders to which it applies and the schema against which to evaluate GraphQL literals, and includes other information needed by the Relay compiler. + Projects are defined in a single [config](#config) file, found [here](https://www.internalfb.com/intern/diffusion/WWW/browse/master/scripts/relay/compiler-rs/config.www.json) and [here](https://www.internalfb.com/intern/diffusion/FBS/browse/master/xplat/relay/compiler-rs/config.xplat.json). + ## Profiler @@ -735,6 +747,7 @@ TODO A collection of all of the GraphQL types that are known to Relay, for a given [project](#project). + ## Schema Sync The GraphQL [schema](#schema) is derived from annotations on Hack classes in the www repository. diff --git a/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-fragments.md b/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-fragments.md index 796428949ec7e..edf2e9b83c25d 100644 --- a/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-fragments.md +++ b/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-fragments.md @@ -24,9 +24,11 @@ When referring to **"refreshing a fragment"**, we mean fetching the *exact* same + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## Using `useRefetchableFragment` diff --git a/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-queries.md b/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-queries.md index cacb088a1c464..6cc8431a76f00 100644 --- a/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-queries.md +++ b/website/versioned_docs/version-v13.0.0/guided-tour/refetching/refreshing-queries.md @@ -25,9 +25,11 @@ When referring to **"refreshing a query"**, we mean fetching the *exact* same da + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## When using `useQueryLoader` / `loadQuery` diff --git a/website/versioned_docs/version-v13.0.0/guides/required-directive.md b/website/versioned_docs/version-v13.0.0/guides/required-directive.md index b0799f710414c..1486fc02e7de7 100644 --- a/website/versioned_docs/version-v13.0.0/guides/required-directive.md +++ b/website/versioned_docs/version-v13.0.0/guides/required-directive.md @@ -119,7 +119,9 @@ fragment MyFrag on Actor { In this situation Relay will generate a union type like: `{__typename: 'User', name: string} | {__typename: '%ignore this%}`. Now you can check the `__typename` field to narrow your object's type down to one that has a non-nullable `name`. + Example diff showing the adoption of this strategy: D24370183 + ### Why not implement this at the schema/server level? diff --git a/website/versioned_docs/version-v14.0.0/glossary/glossary.md b/website/versioned_docs/version-v14.0.0/glossary/glossary.md index 37859796c6091..355d2c9597613 100644 --- a/website/versioned_docs/version-v14.0.0/glossary/glossary.md +++ b/website/versioned_docs/version-v14.0.0/glossary/glossary.md @@ -144,11 +144,15 @@ A directive which declares that a field implements the [connection](#connection) ## Connection + A field implementing the connection spec. See here for more details on the spec, and the section of the guided tour on rendering list data and pagination. + + A field implementing the connection spec. See the section of the guided tour on rendering list data and pagination. + See also [`usePaginationFragment`](../api-reference/use-pagination-fragment). @@ -186,7 +190,9 @@ See the [Thinking in Relay guide](../principles-and-architecture/thinking-in-rel A directive which can be added to a fragment spread or inline fragment to avoid blocking on that fragment's data. + See the [documentation](https://www.internalfb.com/intern/wiki/Relay/Web/incremental-data-delivery-defer-stream/#defer). + ## Definition @@ -420,7 +426,9 @@ A lightweight API for specifying a that a React component should be loaded on de This API is safe to use in entrypoint files. + See [the npm module](https://www.npmjs.com/package/jsresource). + ## Lazy Loading @@ -482,11 +490,15 @@ TODO A mutation is a combination of two things: a mutation on the backend, followed by query against updated data. + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations), and [this article](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/mutation-root-fields/) on defining mutations in your hack code. + + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations). + ## Mutation Root Query @@ -622,7 +634,9 @@ Required because of current limitations on dynamically loading components in Rea For Relay to process a file with a GraphQL literal, it must be included in a project. A project specifies the folders to which it applies and the schema against which to evaluate GraphQL literals, and includes other information needed by the Relay compiler. + Projects are defined in a single [config](#config) file, found [here](https://www.internalfb.com/intern/diffusion/WWW/browse/master/scripts/relay/compiler-rs/config.www.json) and [here](https://www.internalfb.com/intern/diffusion/FBS/browse/master/xplat/relay/compiler-rs/config.xplat.json). + ## Profiler @@ -842,6 +856,7 @@ TODO A collection of all of the GraphQL types that are known to Relay, for a given [project](#project). + ## Schema Sync The GraphQL [schema](#schema) is derived from annotations on Hack classes in the www repository. diff --git a/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-fragments.md b/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-fragments.md index 796428949ec7e..edf2e9b83c25d 100644 --- a/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-fragments.md +++ b/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-fragments.md @@ -24,9 +24,11 @@ When referring to **"refreshing a fragment"**, we mean fetching the *exact* same + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## Using `useRefetchableFragment` diff --git a/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-queries.md b/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-queries.md index 02fe58709fa1c..2f67260ab8014 100644 --- a/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-queries.md +++ b/website/versioned_docs/version-v14.0.0/guided-tour/refetching/refreshing-queries.md @@ -25,9 +25,11 @@ When referring to **"refreshing a query"**, we mean fetching the *exact* same da + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## When using `useQueryLoader` / `loadQuery` diff --git a/website/versioned_docs/version-v14.0.0/guides/required-directive.md b/website/versioned_docs/version-v14.0.0/guides/required-directive.md index b0799f710414c..f21bd1ddd9e11 100644 --- a/website/versioned_docs/version-v14.0.0/guides/required-directive.md +++ b/website/versioned_docs/version-v14.0.0/guides/required-directive.md @@ -119,7 +119,9 @@ fragment MyFrag on Actor { In this situation Relay will generate a union type like: `{__typename: 'User', name: string} | {__typename: '%ignore this%}`. Now you can check the `__typename` field to narrow your object's type down to one that has a non-nullable `name`. + Example diff showing the adoption of this strategy: D24370183 + ### Why not implement this at the schema/server level? @@ -136,6 +138,7 @@ Basically every value returned by Relay is nullable. This is intentional since w _Extracted from [this comment thread](https://fb.workplace.com/groups/cometeng/permalink/937671436726844/?comment_id=937681186725869)._ _Further discussion in [this comment thread](https://fb.workplace.com/groups/cometeng/permalink/937671436726844/?comment_id=938335873327067)._ + ### Can `(action: NONE)` be the default? diff --git a/website/versioned_docs/version-v14.0.0/tutorial/refetchable-fragments.md b/website/versioned_docs/version-v14.0.0/tutorial/refetchable-fragments.md index 9732f90c881ed..2b4317ef3d3a7 100644 --- a/website/versioned_docs/version-v14.0.0/tutorial/refetchable-fragments.md +++ b/website/versioned_docs/version-v14.0.0/tutorial/refetchable-fragments.md @@ -336,7 +336,9 @@ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/interna Besides fragments on types that implement `Node`, you can also refetch fragments that are on `Viewer` (since the viewer is assumed to be stable throughout a session) and that are at the top level of a query (since there’s no field above them that could change identity). + Meta only: Ents marked with [`GraphQLFetchable](https://fb.workplace.com/groups/graphql.fyi/permalink/1539541276187011/)` can also be refetched.]] + diff --git a/website/versioned_docs/version-v15.0.0/api-reference/graphql/graphql-directives.md b/website/versioned_docs/version-v15.0.0/api-reference/graphql/graphql-directives.md index 4d5dd12edb272..a685ef12e5aa0 100644 --- a/website/versioned_docs/version-v15.0.0/api-reference/graphql/graphql-directives.md +++ b/website/versioned_docs/version-v15.0.0/api-reference/graphql/graphql-directives.md @@ -20,10 +20,14 @@ import {FbInternalOnly, OssOnly} from 'docusaurus-plugin-internaldocs-fb/interna Relay uses directives to add additional information to GraphQL documents, which are used by the [Relay compiler](../../guides/compiler/) to generate the appropriate runtime artifacts. These directives only appear in your application code and are removed from requests sent to your GraphQL server. + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. + + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. Additional directives are documented [here](https://www.internalfb.com/intern/wiki/GraphQL/APIs_and_References/Directives/#graphql-standard). + ## `@arguments` diff --git a/website/versioned_docs/version-v15.0.0/glossary/glossary.md b/website/versioned_docs/version-v15.0.0/glossary/glossary.md index 07c3b7816cd26..6e5f07ce16c26 100644 --- a/website/versioned_docs/version-v15.0.0/glossary/glossary.md +++ b/website/versioned_docs/version-v15.0.0/glossary/glossary.md @@ -144,11 +144,14 @@ A directive which declares that a field implements the [connection](#connection) ## Connection + A field implementing the connection spec. See here for more details on the spec, and the section of the guided tour on rendering list data and pagination. + -A field implementing the connection spec. See the section of the guided tour on rendering list data and pagination. + +(\S+) field implementing the connection spec. See the section of the guided tour on rendering list data and pagination. See also [`usePaginationFragment`](../api-reference/use-pagination-fragment). @@ -186,7 +189,9 @@ See the [Thinking in Relay guide](../principles-and-architecture/thinking-in-rel A directive which can be added to a fragment spread or inline fragment to avoid blocking on that fragment's data. + See the [documentation](https://www.internalfb.com/intern/wiki/Relay/Web/incremental-data-delivery-defer-stream/#defer). + ## Definition @@ -420,7 +425,8 @@ A lightweight API for specifying a that a React component should be loaded on de This API is safe to use in entrypoint files. -See [the npm module](https://www.npmjs.com/package/jsresource). + +(\S+) [the npm module](https://www.npmjs.com/package/jsresource). ## Lazy Loading @@ -482,11 +488,14 @@ TODO A mutation is a combination of two things: a mutation on the backend, followed by query against updated data. + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations), and [this article](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/mutation-root-fields/) on defining mutations in your hack code. + -See the [guide on mutations](../guided-tour/updating-data/graphql-mutations). + +(\S+) the [guide on mutations](../guided-tour/updating-data/graphql-mutations). ## Mutation Root Query @@ -622,7 +631,9 @@ Required because of current limitations on dynamically loading components in Rea For Relay to process a file with a GraphQL literal, it must be included in a project. A project specifies the folders to which it applies and the schema against which to evaluate GraphQL literals, and includes other information needed by the Relay compiler. + Projects are defined in a single [config](#config) file, found [here](https://www.internalfb.com/intern/diffusion/WWW/browse/master/scripts/relay/compiler-rs/config.www.json) and [here](https://www.internalfb.com/intern/diffusion/FBS/browse/master/xplat/relay/compiler-rs/config.xplat.json). + ## Profiler @@ -842,6 +853,7 @@ TODO A collection of all of the GraphQL types that are known to Relay, for a given [project](#project). + ## Schema Sync The GraphQL [schema](#schema) is derived from annotations on Hack classes in the www repository. diff --git a/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-fragments.md b/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-fragments.md index 937af7feb3495..8b200ca599ad4 100644 --- a/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-fragments.md +++ b/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-fragments.md @@ -24,9 +24,11 @@ When referring to **"refreshing a fragment"**, we mean fetching the *exact* same + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## Using `useRefetchableFragment` diff --git a/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-queries.md b/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-queries.md index 41af90583486d..98bb479c046df 100644 --- a/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-queries.md +++ b/website/versioned_docs/version-v15.0.0/guided-tour/refetching/refreshing-queries.md @@ -25,9 +25,11 @@ When referring to **"refreshing a query"**, we mean fetching the *exact* same da + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## When using `useQueryLoader` / `loadQuery` diff --git a/website/versioned_docs/version-v15.0.0/guides/relay-resolvers.md b/website/versioned_docs/version-v15.0.0/guides/relay-resolvers.md index 8e44a3f197893..f8a5b7610f15c 100644 --- a/website/versioned_docs/version-v15.0.0/guides/relay-resolvers.md +++ b/website/versioned_docs/version-v15.0.0/guides/relay-resolvers.md @@ -98,9 +98,11 @@ In order for Relay to be able to call a Relay Resolver, it must conform to a set Unlike server resolvers, Relay Resolvers may return any JavaScript value. This includes classes, functions and arrays. However, we generally encourage having Relay Resolvers return scalar values and only returning more complex JavaScript values (like functions) as an escape hatch. + ## Lint Rule In many cases, the contents of the docblock can be derived from the javascript implementation. In those cases, the [`relay-resolvers`](https://www.internalfb.com/eslint/relay-resolvers) ESLint rule rule will offer auto-fixes to derive the docblock from the implementation and ensure that the two remain in sync. The lint rule also enforces a naming convention for resolver function and modules names. + ## How They Work diff --git a/website/versioned_docs/version-v15.0.0/guides/required-directive.md b/website/versioned_docs/version-v15.0.0/guides/required-directive.md index f6e373f343759..a697a6b961e7e 100644 --- a/website/versioned_docs/version-v15.0.0/guides/required-directive.md +++ b/website/versioned_docs/version-v15.0.0/guides/required-directive.md @@ -188,7 +188,9 @@ fragment MyFrag on Actor { In this situation Relay will generate a union type like: `{__typename: 'User', name: string} | {__typename: '%ignore this%}`. Now you can check the `__typename` field to narrow your object's type down to one that has a non-nullable `name`. + Example diff showing the adoption of this strategy: D24370183 + ### Why not implement this at the schema/server level? diff --git a/website/versioned_docs/version-v15.0.0/tutorial/refetchable-fragments.md b/website/versioned_docs/version-v15.0.0/tutorial/refetchable-fragments.md index c94b7744bb33e..88e81a5903f3b 100644 --- a/website/versioned_docs/version-v15.0.0/tutorial/refetchable-fragments.md +++ b/website/versioned_docs/version-v15.0.0/tutorial/refetchable-fragments.md @@ -336,7 +336,9 @@ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/interna Besides fragments on types that implement `Node`, you can also refetch fragments that are on `Viewer` (since the viewer is assumed to be stable throughout a session) and that are at the top level of a query (since there’s no field above them that could change identity). + Meta only: Ents marked with GraphQLFetchable can also be refetched. + diff --git a/website/versioned_docs/version-v16.0.0/api-reference/graphql/graphql-directives.md b/website/versioned_docs/version-v16.0.0/api-reference/graphql/graphql-directives.md index 47dde7dd53a60..4bd480700306c 100644 --- a/website/versioned_docs/version-v16.0.0/api-reference/graphql/graphql-directives.md +++ b/website/versioned_docs/version-v16.0.0/api-reference/graphql/graphql-directives.md @@ -20,10 +20,14 @@ import {FbInternalOnly, OssOnly} from 'docusaurus-plugin-internaldocs-fb/interna Relay uses directives to add additional information to GraphQL documents, which are used by the [Relay compiler](../../guides/compiler/) to generate the appropriate runtime artifacts. These directives only appear in your application code and are removed from requests sent to your GraphQL server. + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. + + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. Additional directives are documented [here](https://www.internalfb.com/intern/wiki/GraphQL/APIs_and_References/Directives/#graphql-standard). + ## `@arguments` diff --git a/website/versioned_docs/version-v16.0.0/glossary/glossary.md b/website/versioned_docs/version-v16.0.0/glossary/glossary.md index 6be2b09a09d5a..fa8fbde9b935b 100644 --- a/website/versioned_docs/version-v16.0.0/glossary/glossary.md +++ b/website/versioned_docs/version-v16.0.0/glossary/glossary.md @@ -144,10 +144,13 @@ A directive which declares that a field implements the [connection](#connection) ## Connection + A field implementing the connection spec. See here for more details on the spec, and the section of the guided tour on rendering list data and pagination. + + A field implementing the connection spec. See the section of the guided tour on rendering list data and pagination. @@ -186,7 +189,9 @@ See the [Thinking in Relay guide](../principles-and-architecture/thinking-in-rel A directive which can be added to a fragment spread or inline fragment to avoid blocking on that fragment's data. + See the [documentation](https://www.internalfb.com/intern/wiki/Relay/Web/incremental-data-delivery-defer-stream/#defer). + ## Definition @@ -420,6 +425,7 @@ A lightweight API for specifying a that a React component should be loaded on de This API is safe to use in entrypoint files. + See [the npm module](https://www.npmjs.com/package/jsresource). @@ -482,10 +488,13 @@ TODO A mutation is a combination of two things: a mutation on the backend, followed by query against updated data. + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations), and [this article](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/mutation-root-fields/) on defining mutations in your hack code. + + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations). @@ -622,7 +631,9 @@ Required because of current limitations on dynamically loading components in Rea For Relay to process a file with a GraphQL literal, it must be included in a project. A project specifies the folders to which it applies and the schema against which to evaluate GraphQL literals, and includes other information needed by the Relay compiler. + Projects are defined in a single [config](#config) file, found [here](https://www.internalfb.com/intern/diffusion/WWW/browse/master/scripts/relay/compiler-rs/config.www.json) and [here](https://www.internalfb.com/intern/diffusion/FBS/browse/master/xplat/relay/compiler-rs/config.xplat.json). + ## Profiler @@ -841,6 +852,7 @@ TODO A collection of all of the GraphQL types that are known to Relay, for a given [project](#project). + ## Schema Sync The GraphQL [schema](#schema) is derived from annotations on Hack classes in the www repository. diff --git a/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-fragments.md b/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-fragments.md index 937af7feb3495..8b200ca599ad4 100644 --- a/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-fragments.md +++ b/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-fragments.md @@ -24,9 +24,11 @@ When referring to **"refreshing a fragment"**, we mean fetching the *exact* same + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## Using `useRefetchableFragment` diff --git a/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-queries.md b/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-queries.md index 41af90583486d..98bb479c046df 100644 --- a/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-queries.md +++ b/website/versioned_docs/version-v16.0.0/guided-tour/refetching/refreshing-queries.md @@ -25,9 +25,11 @@ When referring to **"refreshing a query"**, we mean fetching the *exact* same da + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## When using `useQueryLoader` / `loadQuery` diff --git a/website/versioned_docs/version-v16.0.0/guides/compiler.md b/website/versioned_docs/version-v16.0.0/guides/compiler.md index 2f127a23aa20d..1f57e31b92d22 100644 --- a/website/versioned_docs/version-v16.0.0/guides/compiler.md +++ b/website/versioned_docs/version-v16.0.0/guides/compiler.md @@ -146,6 +146,7 @@ This would produce three generated files, and two `__generated__` directories: ### Importing generated definitions + diff --git a/website/versioned_docs/version-v16.0.0/guides/required-directive.md b/website/versioned_docs/version-v16.0.0/guides/required-directive.md index ce6e02a190277..d1cb1ee91b593 100644 --- a/website/versioned_docs/version-v16.0.0/guides/required-directive.md +++ b/website/versioned_docs/version-v16.0.0/guides/required-directive.md @@ -188,7 +188,9 @@ fragment MyFrag on Actor { In this situation Relay will generate a union type like: `{__typename: 'User', name: string} | {__typename: '%ignore this%}`. Now you can check the `__typename` field to narrow your object's type down to one that has a non-nullable `name`. + Example diff showing the adoption of this strategy: D24370183 + ### Why not implement this at the schema/server level? diff --git a/website/versioned_docs/version-v16.0.0/tutorial/refetchable-fragments.md b/website/versioned_docs/version-v16.0.0/tutorial/refetchable-fragments.md index cf39d0b2776fb..3f4b82a05befc 100644 --- a/website/versioned_docs/version-v16.0.0/tutorial/refetchable-fragments.md +++ b/website/versioned_docs/version-v16.0.0/tutorial/refetchable-fragments.md @@ -336,7 +336,9 @@ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/interna Besides fragments on types that implement `Node`, you can also refetch fragments that are on `Viewer` (since the viewer is assumed to be stable throughout a session) and that are at the top level of a query (since there’s no field above them that could change identity). + Meta only: Ents marked with GraphQLFetchable can also be refetched. + diff --git a/website/versioned_docs/version-v17.0.0/api-reference/graphql/graphql-directives.md b/website/versioned_docs/version-v17.0.0/api-reference/graphql/graphql-directives.md index 3450d789224ca..bc8a019bb836c 100644 --- a/website/versioned_docs/version-v17.0.0/api-reference/graphql/graphql-directives.md +++ b/website/versioned_docs/version-v17.0.0/api-reference/graphql/graphql-directives.md @@ -20,10 +20,14 @@ import {FbInternalOnly, OssOnly} from 'docusaurus-plugin-internaldocs-fb/interna Relay uses directives to add additional information to GraphQL documents, which are used by the [Relay compiler](../../guides/compiler/) to generate the appropriate runtime artifacts. These directives only appear in your application code and are removed from requests sent to your GraphQL server. + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. + + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. Additional directives are documented [here](https://www.internalfb.com/intern/wiki/GraphQL/APIs_and_References/Directives/#graphql-standard). + ## `@arguments` diff --git a/website/versioned_docs/version-v17.0.0/glossary/glossary.md b/website/versioned_docs/version-v17.0.0/glossary/glossary.md index dfed9d5f295de..2d445b05c1b5f 100644 --- a/website/versioned_docs/version-v17.0.0/glossary/glossary.md +++ b/website/versioned_docs/version-v17.0.0/glossary/glossary.md @@ -144,11 +144,15 @@ A directive which declares that a field implements the [connection](#connection) ## Connection + A field implementing the [connection spec](https://relay.dev/graphql/connections.htm). See here for more details on the spec, and the section of the guided tour on rendering list data and pagination. + + A field implementing the [connection spec](https://relay.dev/graphql/connections.htm). See the section of the guided tour on rendering list data and pagination. + See also [`usePaginationFragment`](../api-reference/use-pagination-fragment). @@ -186,7 +190,9 @@ See the [Thinking in Relay guide](../principles-and-architecture/thinking-in-rel A directive which can be added to a fragment spread or inline fragment to avoid blocking on that fragment's data. For more detail refer to GraphQL's [documentation on the @defer directive](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md#defer). + See [Incremental Data Delivery](https://www.internalfb.com/intern/staticdocs/relay/docs/guides/incremental-data-delivery/). + ## Definition @@ -420,6 +426,7 @@ A lightweight API for specifying a that a React component should be loaded on de This API is safe to use in entrypoint files. + See [the npm module](https://www.npmjs.com/package/jsresource). @@ -496,10 +503,13 @@ TODO A mutation is a combination of two things: a mutation on the backend, followed by query against updated data. + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations), and [this article](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/mutation-root-fields/) on defining mutations in your hack code. + + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations). @@ -636,7 +646,9 @@ Required because of current limitations on dynamically loading components in Rea For Relay to process a file with a GraphQL literal, it must be included in a project. A project specifies the folders to which it applies and the schema against which to evaluate GraphQL literals, and includes other information needed by the Relay compiler. + Projects are defined in a single [config](#config) file, found [here](https://www.internalfb.com/intern/diffusion/WWW/browse/master/scripts/relay/compiler-rs/config.www.json) and [here](https://www.internalfb.com/intern/diffusion/FBS/browse/master/xplat/relay/compiler-rs/config.xplat.json). + ## Profiler @@ -855,6 +867,7 @@ TODO A collection of all of the GraphQL types that are known to Relay, for a given [project](#project). + ## Schema Sync The GraphQL [schema](#schema) is derived from annotations on Hack classes in the www repository. diff --git a/website/versioned_docs/version-v17.0.0/guided-tour/refetching/refreshing-fragments.md b/website/versioned_docs/version-v17.0.0/guided-tour/refetching/refreshing-fragments.md index 937af7feb3495..8b200ca599ad4 100644 --- a/website/versioned_docs/version-v17.0.0/guided-tour/refetching/refreshing-fragments.md +++ b/website/versioned_docs/version-v17.0.0/guided-tour/refetching/refreshing-fragments.md @@ -24,9 +24,11 @@ When referring to **"refreshing a fragment"**, we mean fetching the *exact* same + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## Using `useRefetchableFragment` diff --git a/website/versioned_docs/version-v17.0.0/guides/required-directive.md b/website/versioned_docs/version-v17.0.0/guides/required-directive.md index ce6e02a190277..d1cb1ee91b593 100644 --- a/website/versioned_docs/version-v17.0.0/guides/required-directive.md +++ b/website/versioned_docs/version-v17.0.0/guides/required-directive.md @@ -188,7 +188,9 @@ fragment MyFrag on Actor { In this situation Relay will generate a union type like: `{__typename: 'User', name: string} | {__typename: '%ignore this%}`. Now you can check the `__typename` field to narrow your object's type down to one that has a non-nullable `name`. + Example diff showing the adoption of this strategy: D24370183 + ### Why not implement this at the schema/server level? diff --git a/website/versioned_docs/version-v17.0.0/guides/testing-relay-components.md b/website/versioned_docs/version-v17.0.0/guides/testing-relay-components.md index ea4de6f2cc36e..88f444adfa076 100644 --- a/website/versioned_docs/version-v17.0.0/guides/testing-relay-components.md +++ b/website/versioned_docs/version-v17.0.0/guides/testing-relay-components.md @@ -57,7 +57,9 @@ With the `MockPayloadGenerator` and `@relay_test_operation`, we want to get rid **[React Testing Library](https://testing-library.com/react)** is a set of helpers that let you test React components without relying on their implementation details. This approach makes refactoring a breeze and also nudges you towards best practices for accessibility. Although it doesn't provide a way to "shallowly" render a component without its children, a test runner like Jest lets you do this by [mocking](https://reactjs.org/docs/testing-recipes.html#mocking-modules). + Note: The [`ReactTestRenderer`](https://www.npmjs.com/package/react-test-renderer) library has been deprecated since React v18. `ReactTestRenderer` may still be referenced internally as an alternative to React Testing Library. However, when possible, we recommend using React Testing Library (or `@testing-library/react-native`) to test your React applications with Relay. + ## RelayMockEnvironment API Overview diff --git a/website/versioned_docs/version-v17.0.0/tutorial/refetchable-fragments.md b/website/versioned_docs/version-v17.0.0/tutorial/refetchable-fragments.md index d907d620c5674..18d6f46c059ca 100644 --- a/website/versioned_docs/version-v17.0.0/tutorial/refetchable-fragments.md +++ b/website/versioned_docs/version-v17.0.0/tutorial/refetchable-fragments.md @@ -336,7 +336,9 @@ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/interna Besides fragments on types that implement `Node`, you can also refetch fragments that are on `Viewer` (since the viewer is assumed to be stable throughout a session) and that are at the top level of a query (since there’s no field above them that could change identity). + Meta only: Ents marked with GraphQLFetchable can also be refetched. + diff --git a/website/versioned_docs/version-v18.0.0/api-reference/graphql/graphql-directives.md b/website/versioned_docs/version-v18.0.0/api-reference/graphql/graphql-directives.md index a6cb86c92d6f5..ad4056acfae70 100644 --- a/website/versioned_docs/version-v18.0.0/api-reference/graphql/graphql-directives.md +++ b/website/versioned_docs/version-v18.0.0/api-reference/graphql/graphql-directives.md @@ -23,10 +23,14 @@ appropriate runtime artifacts. These directives only appear in your application code and are removed from requests sent to your GraphQL server. + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. + + **Note:** The Relay compiler will maintain any directives supported by your server (such as `@include` or `@skip`) so they remain part of the request to the GraphQL server and won't alter generated runtime artifacts. Additional directives are documented [here](https://www.internalfb.com/intern/wiki/GraphQL/APIs_and_References/Directives/#graphql-standard). + ## `@arguments` diff --git a/website/versioned_docs/version-v18.0.0/api-reference/legacy-apis/legacy-apis.md b/website/versioned_docs/version-v18.0.0/api-reference/legacy-apis/legacy-apis.md deleted file mode 100644 index 0c06eb626c42b..0000000000000 --- a/website/versioned_docs/version-v18.0.0/api-reference/legacy-apis/legacy-apis.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: legacy-apis -title: Legacy APIs -slug: /api-reference/legacy-apis/ -description: API reference for legacy APIs -keywords: - - QueryRenderer - - Container ---- - -API references for our previous legacy APIs are available in our previous docs website: - -- [`QueryRenderer`](https://relay.dev/docs/en/v10.1.3/query-renderer) -- [`Fragment Container`](https://relay.dev/docs/en/v10.1.3/fragment-container) -- [`Refetch Container`](https://relay.dev/docs/en/v10.1.3/refetch-container) -- [`Pagination Container`](https://relay.dev/docs/en/v10.1.3/pagination-container) -- [`Mutations`](https://relay.dev/docs/en/v10.1.3/mutations) -- [`Subscriptions`](https://relay.dev/docs/en/v10.1.3/subscriptions) diff --git a/website/versioned_docs/version-v18.0.0/api-reference/relay-runtime/store.md b/website/versioned_docs/version-v18.0.0/api-reference/relay-runtime/store.md index c5cae4a3ceaaa..e224bc9e420be 100644 --- a/website/versioned_docs/version-v18.0.0/api-reference/relay-runtime/store.md +++ b/website/versioned_docs/version-v18.0.0/api-reference/relay-runtime/store.md @@ -16,6 +16,7 @@ Table of Contents: - [RecordSourceSelectorProxy](#recordsourceselectorproxy) - [RecordProxy](#recordproxy) +- [RecordSourceProxy](#recordsourceproxy) - [ConnectionHandler](#connectionhandler) ## RecordSourceSelectorProxy @@ -46,7 +47,7 @@ const record = store.create(dataID, 'Todo'); ### `delete(dataID: string): void` -Deletes a record from the store given its `dataID`. +Deletes a record from the store given its `dataID`. For existing edges to the deleted record, `undefined` will be returned in the default case even when the value is typed as non-nullable. When [`@throwOnFieldError`](../../guides/throw-on-field-error-directive/) is present, the missing data will throw an error. #### Example @@ -453,6 +454,144 @@ After invalidating a record, any query that references the invalidated record an ```javascript environment.check(query) === 'stale' ``` +## RecordSourceProxy + +The `RecordSourceProxy` serves as an interface to mutate record. + +> **NOTE:** `RecordSourceProxy` exposes many low level APIs that are not typesafe. Users should consider using [typesafe updaters](../../guided-tour/updating-data/typesafe-updaters-faq/), [optimistic updates](../../guided-tour/updating-data/graphql-mutations/#optimistic-updates), and [relay resolvers](../../guides/relay-resolvers/introduction/) instead if their use case can be covered by these alternatives. + +```javascript +interface RecordSourceProxy { + create(dataID: DataID, typeName: string): RecordProxy; + delete(dataID: DataID): void; + get(dataID: DataID): ?RecordProxy; + getRoot(): RecordProxy; + invalidateStore(): void; + readUpdatableFragment( + fragment: UpdatableFragment, + fragmentReference: HasUpdatableSpread, + ): UpdatableData; + readUpdatableQuery( + query: UpdatableQuery, + variables: TVariables, + ): UpdatableData; +} +``` + +### `create(dataID: DataID, typeName: string): RecordProxy` + +Creates a new record in the store given a `dataID` and the `typeName` as defined by the GraphQL schema. Returns a [`RecordProxy`](#recordproxy) which serves as an interface to mutate the newly created record. + +#### Example + +```javascript +const record = store.create(dataID, 'Todo'); +``` + +### `delete(dataID: DataID): void` + +Deletes a record from the store given its `dataID`. For existing edges to the deleted record, `undefined` will be returned in the default case even when the value is typed as non-nullable. When [`@throwOnFieldError`](../../guides/throw-on-field-error-directive/) is present, the missing data will throw an error. + +#### Example + +```javascript +store.delete(dataID); +``` + +### `get(dataID: DataID): ?RecordProxy` + +Retrieves a record from the store given its `dataID`. Returns a [`RecordProxy`](#recordproxy) which serves as an interface to read/mutate the record. + +#### Example + +```javascript +const record = store.get(dataID); +``` + +### `getRoot(): RecordProxy` + +Returns the [`RecordProxy`](#recordproxy) representing the root of the GraphQL document. + +#### Example + +Given the GraphQL document: + +```graphql +viewer { + id +} +``` + +Usage: + +```javascript +// Represents root query +const root = store.getRoot(); +// Get the viewer linked record +const viewer = root.getLinkedRecord('viewer'); +``` + +### `invalidateStore(): void;` + +Globally invalidates the Relay store. This will cause any data that was written to the store before invalidation occurred to be considered stale, and will be considered to require refetch the next time a query is checked with `environment.check()` or is fetched with a `store-or-network` [fetch policy](../../guided-tour/reusing-cached-data/fetch-policies/). + +#### Example + +```javascript +store.invalidateStore(); +``` + +After global invalidation, any query that is checked before refetching it will be considered stale: + +```javascript +environment.check(query) === 'stale' +``` + +### `readUpdatableFragment(fragment: UpdatableFragment,fragmentReference: HasUpdatableSpread): UpdatableData;` + +Fetches an updatable fragment from the store. This updatable fragment's fields can then be imperatively modified to update data in the store. + +For more information on updating the store imperatively, see this [section](../../guided-tour/updating-data/imperatively-modifying-store-data/) of the guided tour. + +#### Example +```javascript +const fragment = graphql` + fragment StoryLikeButton_updatable on Story @updatable { + likeCount + doesViewerLike + } +`; +const { + updatableData +} = store.readUpdatableFragment( + fragment, + story +); +updatableData.likeCount = updatableData.likeCount + 1 +``` + +### `readUpdatableQuery(query: UpdatableQuery,variables: TVariables): UpdatableData` + +Reads an updatable query from the store. This updatable query's fields can be imperatively modified to update data in the store. Unlike `readUpdatableFragment`, you do not need to pass in a `fragmentReference` as an input argument. + +For more information on updating the store imperatively, see this [section](../../guided-tour/updating-data/imperatively-modifying-store-data/) of the guided tour. + +#### Example + +```javascript +const {updatableData} = store.readUpdatableQuery( + graphql` + query NameUpdaterUpdateQuery @updatable { + viewer { + name + } + } + `, + {} +); +const viewer = updatableData.viewer; +viewer.name = newName; +``` ## ConnectionHandler diff --git a/website/versioned_docs/version-v18.0.0/glossary/glossary.md b/website/versioned_docs/version-v18.0.0/glossary/glossary.md index d3c089cde7dd6..a6b2974f4d819 100644 --- a/website/versioned_docs/version-v18.0.0/glossary/glossary.md +++ b/website/versioned_docs/version-v18.0.0/glossary/glossary.md @@ -144,10 +144,13 @@ A directive which declares that a field implements the [connection](#connection) ## Connection + A field implementing the [connection spec](https://relay.dev/graphql/connections.htm). See here for more details on the spec, and the section of the guided tour on rendering list data and pagination. + + A field implementing the [connection spec](https://relay.dev/graphql/connections.htm). See the section of the guided tour on rendering list data and pagination. @@ -186,7 +189,9 @@ See the [Thinking in Relay guide](../principles-and-architecture/thinking-in-rel A directive which can be added to a fragment spread or inline fragment to avoid blocking on that fragment's data. For more detail refer to GraphQL's [documentation on the @defer directive](https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md#defer). + See [Incremental Data Delivery](https://www.internalfb.com/intern/staticdocs/relay/docs/guides/incremental-data-delivery/). + ## Definition @@ -420,6 +425,7 @@ A lightweight API for specifying a that a React component should be loaded on de This API is safe to use in entrypoint files. + See [the npm module](https://www.npmjs.com/package/jsresource). @@ -496,10 +502,13 @@ TODO A mutation is a combination of two things: a mutation on the backend, followed by query against updated data. + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations), and [this article](https://www.internalfb.com/intern/wiki/Graphql-for-hack-developers/mutation-root-fields/) on defining mutations in your hack code. + + See the [guide on mutations](../guided-tour/updating-data/graphql-mutations). @@ -636,7 +645,9 @@ Required because of current limitations on dynamically loading components in Rea For Relay to process a file with a GraphQL literal, it must be included in a project. A project specifies the folders to which it applies and the schema against which to evaluate GraphQL literals, and includes other information needed by the Relay compiler. + Projects are defined in a single [config](#config) file, found [here](https://www.internalfb.com/intern/diffusion/WWW/browse/master/scripts/relay/compiler-rs/config.www.json) and [here](https://www.internalfb.com/intern/diffusion/FBS/browse/master/xplat/relay/compiler-rs/config.xplat.json). + ## Profiler @@ -855,6 +866,7 @@ TODO A collection of all of the GraphQL types that are known to Relay, for a given [project](#project). + ## Schema Sync The GraphQL [schema](#schema) is derived from annotations on Hack classes in the www repository. diff --git a/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refetching-queries-with-different-data.md b/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refetching-queries-with-different-data.md index 6640c5a9c101c..af6a18239fabc 100644 --- a/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refetching-queries-with-different-data.md +++ b/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refetching-queries-with-different-data.md @@ -130,6 +130,7 @@ function App(props: Props) { const refetch = useCallback(() => { if (isRefetching) { return; } setIsRefetching(true); + const variables = { id: 'different-id' }; // fetchQuery will fetch the query and write // the data to the Relay store. This will ensure @@ -146,7 +147,7 @@ function App(props: Props) { // At this point the data for the query should // be cached, so we use the 'store-only' // fetchPolicy to avoid suspending. - loadQuery({id: 'different-id'}, {fetchPolicy: 'store-only'}); + loadQuery(variables, {fetchPolicy: 'store-only'}); }, error: () => { setIsRefetching(false); @@ -292,6 +293,7 @@ function App(props: Props) { const refetch = useCallback(() => { if (isRefreshing) { return; } setIsRefreshing(true); + const variables = { id: 'different-id' }; // fetchQuery will fetch the query and write // the data to the Relay store. This will ensure @@ -313,7 +315,7 @@ function App(props: Props) { fetchKey: (prev?.options.fetchKey ?? 0) + 1, fetchPolicy: 'store-only', }, - variables: {id: 'different-id'} + variables, })); }, error: () => { diff --git a/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-fragments.md b/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-fragments.md index 937af7feb3495..8b200ca599ad4 100644 --- a/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-fragments.md +++ b/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-fragments.md @@ -24,9 +24,11 @@ When referring to **"refreshing a fragment"**, we mean fetching the *exact* same + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). + ## Using `useRefetchableFragment` diff --git a/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-queries.md b/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-queries.md index 41af90583486d..7e683fe30ba7f 100644 --- a/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-queries.md +++ b/website/versioned_docs/version-v18.0.0/guided-tour/refetching/refreshing-queries.md @@ -25,6 +25,7 @@ When referring to **"refreshing a query"**, we mean fetching the *exact* same da + If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). diff --git a/website/versioned_docs/version-v18.0.0/guided-tour/updating-data/typesafe-updaters-faq.md b/website/versioned_docs/version-v18.0.0/guided-tour/updating-data/typesafe-updaters-faq.md index 22a2f46ca770f..3bc6a5c393460 100644 --- a/website/versioned_docs/version-v18.0.0/guided-tour/updating-data/typesafe-updaters-faq.md +++ b/website/versioned_docs/version-v18.0.0/guided-tour/updating-data/typesafe-updaters-faq.md @@ -32,6 +32,8 @@ Is something missing from this Q&A? Are you confused? Would you like help adopti Typesafe updaters is the name given to a project to provide a typesafe and ergonomic alternative to the existing APIs for imperatively updating data in the Relay store. +For example, [`readUpdatableFragment`](../../../api-reference/store/#readupdatablefragmentfragment-updatablefragmenttfragmenttype-tdatafragmentreference-hasupdatablespreadtfragmenttype-updatabledatatdata) and [`readUpdatableQuery`](../../../api-reference/store/#readupdatablequeryquery-updatablequerytvariables-tdatavariables-tvariables-updatabledatatdata) are two typesafe updaters that the store exposes. + ## Why? Relay provides typesafe and ergonomic APIs for fetching and managing data that originates on the server. In addition, Relay provides the ability to define local-only fields in **client schema extensions**. However, the APIs for mutating the data in these fields has hitherto been verbose and not ergonomic, meaning that we could not recommend Relay as a solution for managing local state. @@ -40,16 +42,12 @@ Relay provides typesafe and ergonomic APIs for fetching and managing data that o The pre-existing APIs are verbose and not typesafe. They make it easy to make a variety of mistakes and require that the developer understand a new set of APIs only when writing updaters. -Typesafe updaters is a set of APIs that are typesafe and (hopefully) more ergonomic. They leverage well-known Relay idioms (queries, fragments, type refinement) and use getters and setters instead of requiring that the developer learn about a set of methods that are unused elsewhere. +Typesafe updaters is a set of APIs that are typesafe and more ergonomic. They leverage well-known Relay idioms (queries, fragments, type refinement) and use getters and setters instead of requiring that the developer learn about a set of methods that are unused elsewhere. ## How does a developer use typesafe updaters? With typesafe updaters, a developers writes an updatable query or a fragment that specifies the data to imperatively update. Then, the developer reads out that data from the store, returning a so-called **updatable proxy**. Then, the developer mutates that updatable proxy. Mutating that updatable proxy using setters (e.g. `updatableData.name = "Godzilla"`) results in calls to the old API, but with added type safety. -## Why are these labeled `_EXPERIMENTAL`? - -These are de facto not experimental. We encourage you to use them when writing new code! This suffix will be removed soon. - ## What is an updatable query or fragment? An updatable query or fragment is a query or fragment that has the `@updatable` directive. @@ -77,7 +75,7 @@ You should select that field in both a regular query/fragment **and** in an upda ## Where do I get a `store`? -The classes `RelayRecordSourceSelectorProxy` and `RelayRecordSourceProxy` contain the methods `readUpdatableQuery` and `readUpdatableFragment`. One can acquire an instance of these classes: +The classes `RelayRecordSourceSelectorProxy`, `RecordSourceProxy` and `RelayRecordSourceProxy` contain the methods `readUpdatableQuery` and `readUpdatableFragment`. One can acquire an instance of these classes: * In updaters of mutations and subscriptions * In optimistic updaters of mutations diff --git a/website/versioned_docs/version-v18.0.0/guides/relay-resolvers/defining-types.md b/website/versioned_docs/version-v18.0.0/guides/relay-resolvers/defining-types.md index 128e3183739a3..66471ade373ca 100644 --- a/website/versioned_docs/version-v18.0.0/guides/relay-resolvers/defining-types.md +++ b/website/versioned_docs/version-v18.0.0/guides/relay-resolvers/defining-types.md @@ -125,7 +125,9 @@ interface IUser { You could define two (or more) concrete resolver types that implement the IUser interface by adding annotations in the docblock (the same applies for unions). + Note, support for abstract types is not available for relay resolvers in Flow syntax (yet). + + Example diff showing the adoption of this strategy: D24370183 + ### Why not implement this at the schema/server level? diff --git a/website/versioned_docs/version-v18.0.0/guides/testing-relay-components.md b/website/versioned_docs/version-v18.0.0/guides/testing-relay-components.md index ea4de6f2cc36e..88f444adfa076 100644 --- a/website/versioned_docs/version-v18.0.0/guides/testing-relay-components.md +++ b/website/versioned_docs/version-v18.0.0/guides/testing-relay-components.md @@ -57,7 +57,9 @@ With the `MockPayloadGenerator` and `@relay_test_operation`, we want to get rid **[React Testing Library](https://testing-library.com/react)** is a set of helpers that let you test React components without relying on their implementation details. This approach makes refactoring a breeze and also nudges you towards best practices for accessibility. Although it doesn't provide a way to "shallowly" render a component without its children, a test runner like Jest lets you do this by [mocking](https://reactjs.org/docs/testing-recipes.html#mocking-modules). + Note: The [`ReactTestRenderer`](https://www.npmjs.com/package/react-test-renderer) library has been deprecated since React v18. `ReactTestRenderer` may still be referenced internally as an alternative to React Testing Library. However, when possible, we recommend using React Testing Library (or `@testing-library/react-native`) to test your React applications with Relay. + ## RelayMockEnvironment API Overview diff --git a/website/versioned_docs/version-v18.0.0/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md b/website/versioned_docs/version-v18.0.0/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md index fc9d1dc248aea..a8627c0b15333 100644 --- a/website/versioned_docs/version-v18.0.0/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md +++ b/website/versioned_docs/version-v18.0.0/migration-and-compatibility/relay-hooks-and-legacy-container-apis.md @@ -17,7 +17,7 @@ import DocsRating from '@site/src/core/DocsRating'; ## Compatibility between Relay Hooks and Containers -Relay Hooks are fully compatible with Relay's [container-based APIs](../../api-reference/legacy-apis/), meaning that containers can render components that use Hooks, and vice-versa. +Relay Hooks are fully compatible with Relay's container-based APIs, meaning that containers can render components that use Hooks, and vice-versa. This means that you can adopt Relay Hooks incrementally, either by using them exclusively for new code, or by migrating specific parts of your app, without affecting the rest of your existing application. diff --git a/website/versioned_docs/version-v18.0.0/tutorial/refetchable-fragments.md b/website/versioned_docs/version-v18.0.0/tutorial/refetchable-fragments.md index d907d620c5674..18d6f46c059ca 100644 --- a/website/versioned_docs/version-v18.0.0/tutorial/refetchable-fragments.md +++ b/website/versioned_docs/version-v18.0.0/tutorial/refetchable-fragments.md @@ -336,7 +336,9 @@ import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/interna Besides fragments on types that implement `Node`, you can also refetch fragments that are on `Viewer` (since the viewer is assumed to be stable throughout a session) and that are at the top level of a query (since there’s no field above them that could change identity). + Meta only: Ents marked with GraphQLFetchable can also be refetched. + diff --git a/website/versioned_sidebars/version-v18.0.0-sidebars.json b/website/versioned_sidebars/version-v18.0.0-sidebars.json index eabed556a1667..aeeffc9365279 100644 --- a/website/versioned_sidebars/version-v18.0.0-sidebars.json +++ b/website/versioned_sidebars/version-v18.0.0-sidebars.json @@ -119,8 +119,7 @@ "api-reference/relay-resolvers/runtime-functions" ] }, - "api-reference/graphql/graphql-directives", - "api-reference/legacy-apis/legacy-apis" + "api-reference/graphql/graphql-directives" ], "Testing and Debugging": [ "guides/testing-relay-components", diff --git a/website/yarn.lock b/website/yarn.lock index a96f63765c587..a60ad9408fe14 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2806,7 +2806,6 @@ "@docusaurus/types" "2.4.3" "@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2": - name react-loadable version "5.5.2" resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce" integrity sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ== @@ -5775,9 +5774,9 @@ dom-converter@^0.2.0: utila "~0.4" dom-iterator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dom-iterator/-/dom-iterator-1.0.0.tgz#9c09899846ec41c2d257adc4d6015e4759ef05ad" - integrity sha512-7dsMOQI07EMU98gQM8NSB3GsAiIeBYIPKpnxR3c9xOvdvBjChAcOM0iJ222I3p5xyiZO9e5oggkNaCusuTdYig== + version "1.0.2" + resolved "https://registry.yarnpkg.com/dom-iterator/-/dom-iterator-1.0.2.tgz#6b239349ccadbd595055da5e0a7386cce9f0aa7b" + integrity sha512-BMelEjhy08OpoWF3v/jrPtx7PZCyP1VM9yiB7rJk19UVmt7zTN5rqoC0Jea+EyT0M6v/VokL0LxIlGLUOBJZ2g== dependencies: component-props "1.1.1" component-xor "0.0.4" diff --git a/yarn.lock b/yarn.lock index 3cdabc0b51ec6..c895ec30b9ff4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1334,15 +1334,6 @@ "@jridgewell/set-array" "^1.0.0" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - "@jridgewell/gen-mapping@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" @@ -1381,14 +1372,6 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/source-map@^0.3.3": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" - integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" @@ -1407,14 +1390,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@jridgewell/trace-mapping@^0.3.17": - version "0.3.20" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" - integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@jridgewell/trace-mapping@^0.3.9": version "0.3.14" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" @@ -1527,27 +1502,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/eslint-scope@^3.7.3": - version "3.7.6" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.6.tgz#585578b368ed170e67de8aae7b93f54a1b2fdc26" - integrity sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.44.5" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.5.tgz#24d7f3b07aff47a13b570efd5c52d96f38cd352e" - integrity sha512-Ol2eio8LtD/tGM4Ga7Jb83NuFwEv3NqvssSlifXL9xuFpSyQZw0ecmm2Kux6iU0KxQmp95hlPmGCzGJ0TCFeRA== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.3.tgz#2be19e759a3dd18c79f9f436bd7363556c1a73dd" - integrity sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ== - "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -1583,11 +1537,6 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.8": - version "7.0.14" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.14.tgz#74a97a5573980802f32c8e47b663530ab3b6b7d1" - integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw== - "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -1681,137 +1630,6 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" - integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== - -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== - -"@webassemblyjs/helper-buffer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" - integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== - -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== - -"@webassemblyjs/helper-wasm-section@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" - integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== - -"@webassemblyjs/wasm-edit@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" - integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-opt" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - "@webassemblyjs/wast-printer" "1.11.6" - -"@webassemblyjs/wasm-gen@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" - integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" - integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - -"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" - integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" - integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - abab@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" @@ -1825,11 +1643,6 @@ acorn-globals@^7.0.0: acorn "^8.1.0" acorn-walk "^8.0.2" -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== - acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -1847,7 +1660,7 @@ acorn@^8.1.0, acorn@^8.11.0, acorn@^8.8.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== -acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: +acorn@^8.9.0: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== @@ -1867,12 +1680,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1913,11 +1721,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -2026,11 +1829,6 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== -array-differ@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" - integrity sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ== - array-each@^1.0.0, array-each@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" @@ -2081,11 +1879,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -2258,12 +2051,12 @@ babel-plugin-polyfill-regenerator@^0.6.1: dependencies: "@babel/helper-define-polyfill-provider" "^0.6.2" -babel-plugin-syntax-hermes-parser@0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.24.0.tgz#79d0c73daae7bd7d4b07f64ee281c75aa48845cf" - integrity sha512-J4wETqz7ehbyYl2uge65zsfr0Ue+0yJYYMMkGAWpZc0fB02z4JAcx+mJEXVU14yiihGwqVUlR7oS4/gDYOxUdA== +babel-plugin-syntax-hermes-parser@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz#58b539df973427fcfbb5176a3aec7e5dee793cb0" + integrity sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ== dependencies: - hermes-parser "0.24.0" + hermes-parser "0.25.1" babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: version "7.0.0-beta.0" @@ -2373,11 +2166,6 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -beeper@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" - integrity sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA== - binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -2414,16 +2202,6 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.14.5: - version "4.22.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" - integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== - dependencies: - caniuse-lite "^1.0.30001541" - electron-to-chromium "^1.4.535" - node-releases "^2.0.13" - update-browserslist-db "^1.0.13" - browserslist@^4.20.2: version "4.21.2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.2.tgz#59a400757465535954946a400b841ed37e2b4ecf" @@ -2533,22 +2311,11 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001366, caniuse-lite@^1.0.30001541, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001646: +caniuse-lite@^1.0.30001366, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001646: version "1.0.30001655" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz" integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== -chalk@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2586,11 +2353,6 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -2639,21 +2401,11 @@ clone-buffer@^1.0.0: resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" integrity sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g== -clone-stats@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" - integrity sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA== - clone-stats@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" integrity sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag== -clone@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== - clone@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" @@ -2736,11 +2488,6 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - common-tags@^1.4.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -2766,13 +2513,6 @@ concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" -concat-with-sourcemaps@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" - integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== - dependencies: - source-map "^0.6.1" - convert-source-map@^1.5.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" @@ -2911,11 +2651,6 @@ data-urls@^3.0.2: whatwg-mimetype "^3.0.0" whatwg-url "^11.0.0" -dateformat@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" - integrity sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw== - debug@4: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" @@ -3095,13 +2830,6 @@ domexception@^4.0.0: dependencies: webidl-conversions "^7.0.0" -duplexer2@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - integrity sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g== - dependencies: - readable-stream "~1.1.9" - duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" @@ -3125,11 +2853,6 @@ electron-to-chromium@^1.4.188: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.195.tgz#139b2d95a42a3f17df217589723a1deac71d1473" integrity sha512-vefjEh0sk871xNmR5whJf9TEngX+KTKS3hOHpjoMpauKkwlGwtMz1H8IaIjAT/GNnX0TbGwAdmVoXCAzXf+PPg== -electron-to-chromium@^1.4.535: - version "1.4.557" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.557.tgz#f3941b569c82b7bb909411855c6ff9bfe1507829" - integrity sha512-6x0zsxyMXpnMJnHrondrD3SuAeKcwij9S+83j2qHAQPXbGTDDfgImzzwgGlzrIcXbHQ42tkG4qA6U860cImNhw== - electron-to-chromium@^1.4.668: version "1.4.748" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.748.tgz#aa7d4f2f3eac3a6a863cd1779bd4682b4bb68ed5" @@ -3162,26 +2885,11 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.4: dependencies: once "^1.4.0" -enhanced-resolve@^5.15.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" - integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - entities@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== -errno@^0.1.3: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.1" - error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3218,11 +2926,6 @@ es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19 string.prototype.trimstart "^1.0.5" unbox-primitive "^1.0.2" -es-module-lexer@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.1.tgz#c1b0dd5ada807a3b3155315911f364dc4e909db1" - integrity sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q== - es-shim-unscopables@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" @@ -3285,7 +2988,7 @@ escalade@^3.1.2: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -3412,10 +3115,10 @@ eslint-plugin-node@^11.1.0: resolve "^1.10.1" semver "^6.1.0" -eslint-plugin-react-hooks@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" - integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== +eslint-plugin-react-hooks@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3" + integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg== eslint-plugin-react@7.30.1: version "7.30.1" @@ -3453,7 +3156,7 @@ eslint-rule-composer@^0.3.0: resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== -eslint-scope@5.1.1, eslint-scope@^5.1.1: +eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3590,11 +3293,6 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -events@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -3687,7 +3385,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fancy-log@^1.1.0, fancy-log@^1.3.2, fancy-log@^1.3.3: +fancy-log@^1.3.2: version "1.3.3" resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== @@ -3864,10 +3562,10 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== -flow-bin@^0.253.0: - version "0.253.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.253.0.tgz#5b5150ad9a68560c1b8ace225b7d30e1a6469346" - integrity sha512-D1EY3n+YNTG9PK15VGHuwxTPMJncUizVDjFS7vm6mIj1qoo7DDDMa8poEgpuZS0yKVBMWoM2IXlWYyZ9v5MVvg== +flow-bin@^0.266.1: + version "0.266.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.266.1.tgz#8939be6fbd681c4ef8dc4873b22f4b79be76cb0a" + integrity sha512-c1lg1E8SDcuPSkrOeH0JTcNKMZOzXvqX2DuuXJ0amZec15uyuIi8QlGTO3OzYssMT/kwFdo5vviJqSUI/BNFbw== flush-write-stream@^1.0.2: version "1.1.1" @@ -4028,11 +3726,6 @@ glob-stream@^6.1.0: to-absolute-glob "^2.0.0" unique-stream "^2.0.2" -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - glob-watcher@^5.0.3, glob-watcher@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-6.0.0.tgz#8565341978a92233fb3881b8857b4d1e9c6bf080" @@ -4172,45 +3865,11 @@ gulp-cli@^2.2.0: v8flags "^3.2.0" yargs "^7.1.0" -gulp-header@2.0.9: - version "2.0.9" - resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-2.0.9.tgz#8b432c4d4379dee6788845b16785b09c7675af84" - integrity sha512-LMGiBx+qH8giwrOuuZXSGvswcIUh0OiioNkUpLhNyvaC6/Ga8X6cfAeme2L5PqsbXMhL8o8b/OmVqIQdxprhcQ== - dependencies: - concat-with-sourcemaps "^1.1.0" - lodash.template "^4.5.0" - map-stream "0.0.7" - through2 "^2.0.0" - gulp-rename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-2.0.0.tgz#9bbc3962b0c0f52fc67cd5eaff6c223ec5b9cf6c" integrity sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ== -gulp-util@3.0.8: - version "3.0.8" - resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" - integrity sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw== - dependencies: - array-differ "^1.0.0" - array-uniq "^1.0.2" - beeper "^1.0.0" - chalk "^1.0.0" - dateformat "^2.0.0" - fancy-log "^1.1.0" - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash._reescape "^3.0.0" - lodash._reevaluate "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.template "^3.0.0" - minimist "^1.1.0" - multipipe "^0.1.2" - object-assign "^3.0.0" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl "^0.5.0" - gulp@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.2.tgz#543651070fd0f6ab0a0650c6a3e6ff5a7cb09caa" @@ -4228,13 +3887,6 @@ gulplog@^1.0.0: dependencies: glogg "^1.0.0" -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -4250,13 +3902,6 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - integrity sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw== - dependencies: - sparkles "^1.0.0" - has-property-descriptors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" @@ -4314,26 +3959,26 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hermes-eslint@0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.24.0.tgz#a86b723bfb0d12ac3031b66c4b861f0ff2d582f3" - integrity sha512-PS/b1MO7NxVBwnxaPvcd3MGsXlt7B0S9gfL7mIbMDIf1A0tYsR09/i/Sl8BHhMX9zb99h499b4POitmr8soQFQ== +hermes-eslint@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.25.1.tgz#e7d2d845256705d5e2d5cf69dc79032ac3921bb3" + integrity sha512-nPz9+oyejT1zsIwoJ2pWdUvLcN1i+tbaWCOD8PpNBYQtnHXaPXImZp/6zZHnm3bo/DoFcAgh8+SNcxLFxh7m/A== dependencies: esrecurse "^4.3.0" - hermes-estree "0.24.0" - hermes-parser "0.24.0" + hermes-estree "0.25.1" + hermes-parser "0.25.1" -hermes-estree@0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.24.0.tgz#487dc1ddc0bae698c2d79f34153ac9bf62d7b3c0" - integrity sha512-LyoXLB7IFzeZW0EvAbGZacbxBN7t6KKSDqFJPo3Ydow7wDlrDjXwsdiAHV6XOdvEN9MEuWXsSIFN4tzpyrXIHw== +hermes-estree@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480" + integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw== -hermes-parser@0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.24.0.tgz#2ed19d079efc0848eb1f800f0c393a074c4696fb" - integrity sha512-IJooSvvu2qNRe7oo9Rb04sUT4omtZqZqf9uq9WM25Tb6v3usmvA93UqfnnoWs5V0uYjEl9Al6MNU10MCGKLwpg== +hermes-parser@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1" + integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA== dependencies: - hermes-estree "0.24.0" + hermes-estree "0.25.1" homedir-polyfill@^1.0.1: version "1.0.3" @@ -4440,7 +4085,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4770,11 +4415,6 @@ is-windows@^1.0.1, is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -5202,15 +4842,6 @@ jest-watcher@^29.7.0: jest-util "^29.7.0" string-length "^4.0.1" -jest-worker@^27.4.5: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - jest-worker@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" @@ -5293,7 +4924,7 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: +json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== @@ -5446,11 +5077,6 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader-runner@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" - integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== - locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -5473,87 +5099,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - integrity sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ== - -lodash._basetostring@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" - integrity sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA== - -lodash._basevalues@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" - integrity sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg== - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - integrity sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA== - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - integrity sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ== - -lodash._reescape@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" - integrity sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ== - -lodash._reevaluate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" - integrity sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w== - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== - -lodash._root@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - integrity sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ== - -lodash.clone@^4.3.2: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" - integrity sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg== - lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.escape@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" - integrity sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ== - dependencies: - lodash._root "^3.0.0" - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - integrity sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ== - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - integrity sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ== - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -5564,54 +5114,6 @@ lodash.mergewith@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - integrity sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw== - -lodash.some@^4.2.2: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" - integrity sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ== - -lodash.template@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" - integrity sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ== - dependencies: - lodash._basecopy "^3.0.0" - lodash._basetostring "^3.0.0" - lodash._basevalues "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.keys "^3.0.0" - lodash.restparam "^3.0.0" - lodash.templatesettings "^3.0.0" - -lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" - integrity sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -5669,11 +5171,6 @@ map-cache@^0.2.0, map-cache@^0.2.2: resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== -map-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" - integrity sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ== - map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -5691,14 +5188,6 @@ matchdep@^2.0.0: resolve "^1.4.0" stack-trace "0.0.10" -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -5741,7 +5230,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27: +mime-types@^2.1.12: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -5760,7 +5249,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== @@ -5788,13 +5277,6 @@ ms@^2.1.1, ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multipipe@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" - integrity sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q== - dependencies: - duplexer2 "0.0.2" - mute-stdout@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" @@ -5822,11 +5304,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - next-tick@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" @@ -5844,11 +5321,6 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" - integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== - node-releases@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" @@ -5915,11 +5387,6 @@ nwsapi@^2.2.2: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - integrity sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ== - object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -6318,14 +5785,14 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-plugin-hermes-parser@0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/prettier-plugin-hermes-parser/-/prettier-plugin-hermes-parser-0.24.0.tgz#b6a03a2d88e0320d05fc788598b1f0e21e9f7eb6" - integrity sha512-5ocvjexclFaU/qaiw3EW36G5I3H5iX8FQKNWwbls3qXVdzWGMaHNt61xxMzne0E9Unpk9EpMzpijGxgPGb94pw== +prettier-plugin-hermes-parser@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/prettier-plugin-hermes-parser/-/prettier-plugin-hermes-parser-0.25.1.tgz#f7e82357f7fdcf5fcdf9e06dcc3bbafe03ed61eb" + integrity sha512-qVsgSt1ZLz7sxQyMmLM3b8JYIcUt4pkE+OCMEoUTe5G87ghNe9lluYMy7ptu1h0f3fAZ+zkifUV3JojMmQcKkg== dependencies: - hermes-estree "0.24.0" - hermes-parser "0.24.0" - prettier-plugin-hermes-parser "0.24.0" + hermes-estree "0.25.1" + hermes-parser "0.25.1" + prettier-plugin-hermes-parser "0.25.1" prettier@2.8.8: version "2.8.8" @@ -6389,11 +5856,6 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== - psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -6441,24 +5903,17 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== +react-dom@0.0.0-experimental-7670501b-20241124: + version "0.0.0-experimental-7670501b-20241124" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-7670501b-20241124.tgz#2d94f677386cb524df568deb7972623de2e7c3fb" + integrity sha512-150W/wDCbC/W8WpDowFCY3294u1WYTnpgc4owl3BVzsAkBeGxgKN1CNT4IC1xNI05CGDDG9lyGE9M0wvDj0fTQ== dependencies: - safe-buffer "^5.1.0" + scheduler "0.0.0-experimental-7670501b-20241124" -react-dom@0.0.0-experimental-4beb1fd8-20241118: - version "0.0.0-experimental-4beb1fd8-20241118" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-4beb1fd8-20241118.tgz#bf51483d52faea0618abef7d7eab681eea328ac7" - integrity sha512-/Gs2N/6hiuwqf2uuJ3UN/PWxpIncbuY7XY/IynlB2oNpopeV+x1MMXfNdse8TiPkpgg9aw+VUfQUlLPC52bKiQ== - dependencies: - scheduler "0.0.0-experimental-4beb1fd8-20241118" - -react-is@0.0.0-experimental-4beb1fd8-20241118: - version "0.0.0-experimental-4beb1fd8-20241118" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-0.0.0-experimental-4beb1fd8-20241118.tgz#b6831c4ea841c994cc4a2f8c516ec8bbfe6b93ec" - integrity sha512-7JE3PtW4zpMYdp1bTXKNmz2t0jzaqc3frMWbvbuZmhif5ndtYx5oCGhfnbm6S5ZeTNKe4GXsN5D73QtZClfepQ== +react-is@0.0.0-experimental-7670501b-20241124: + version "0.0.0-experimental-7670501b-20241124" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-0.0.0-experimental-7670501b-20241124.tgz#e6ca59dbe174a84973fc1fcb93c80e70fd954e92" + integrity sha512-PnwSMy9ku+6ZQbUNXA9bF9y4LyVQTKfOLAQYe/YcM2D+6KdENLKFp+CBQIuqOo5iC5b89bYyDSM3FJ7GNh0byA== react-is@^16.13.1: version "16.13.1" @@ -6475,23 +5930,23 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-refresh@0.0.0-experimental-4beb1fd8-20241118: - version "0.0.0-experimental-4beb1fd8-20241118" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.0.0-experimental-4beb1fd8-20241118.tgz#0605b592bbbdfeee13b49f14fea5cb0247100667" - integrity sha512-McWSxqM2X1KeDxMZsKOvecqs0lqa8ToHn8uFA1uKGn5VpD1zpqGS81c9ZMiDI4KLIC1jt0Q0Na0XPNMUNpyi9A== +react-refresh@0.0.0-experimental-7670501b-20241124: + version "0.0.0-experimental-7670501b-20241124" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.0.0-experimental-7670501b-20241124.tgz#eae264af9c555810115c06e2802119da0ddf0e0b" + integrity sha512-GfDDetNKgJr9Y/Ny2vbIvZkBRuMyVdKRp9xWQDUgmlzl/Mr4oPYlDJacCxctn0G/UT9FnsqQOOhu7Vy7NF8r7w== -react-test-renderer@0.0.0-experimental-4beb1fd8-20241118: - version "0.0.0-experimental-4beb1fd8-20241118" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-0.0.0-experimental-4beb1fd8-20241118.tgz#fbf42d72d3049ae17c19d589cede3c2632a34ea1" - integrity sha512-/SWsL+FRxDgDLT8b1/yG8eOSl/lw2k8f0fhb7oTzwU1ArjimKy0mU2sWMr46U5ZP6NZ1iZyQlNJ/q2PwyjCT7A== +react-test-renderer@0.0.0-experimental-7670501b-20241124: + version "0.0.0-experimental-7670501b-20241124" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-0.0.0-experimental-7670501b-20241124.tgz#651782a2fa4a9ba03c64d18ca7f97f759f266b89" + integrity sha512-/lzy5JWNO6CiKIJOmlpVSyFuhVMqEMAwsSH8LoLgBpaxWUlA88CWJPhJxU9yN1eEVkSRb3O9umqtfNeqT+bYHA== dependencies: - react-is "0.0.0-experimental-4beb1fd8-20241118" - scheduler "0.0.0-experimental-4beb1fd8-20241118" + react-is "0.0.0-experimental-7670501b-20241124" + scheduler "0.0.0-experimental-7670501b-20241124" -react@0.0.0-experimental-4beb1fd8-20241118: - version "0.0.0-experimental-4beb1fd8-20241118" - resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-4beb1fd8-20241118.tgz#1585771bb5246a2a9828700997d90db9adb0eeba" - integrity sha512-SojDx9IQZXRbze+BNoLRiBDblVTMRebpOZyU2QyRk4ptJob78QiROi58uuE7yxrFMDQN4kBl6tqYkSwQaIM2nQ== +react@0.0.0-experimental-7670501b-20241124: + version "0.0.0-experimental-7670501b-20241124" + resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-7670501b-20241124.tgz#056d77fa46ba89238a7d1fff6101b688802bdac7" + integrity sha512-A7FwEzKrEj3Trjm+EQAgGYaBriKgIfRf2q6byM8RpEip1PDG/6g8giycr0Y03JLSlkKNDoHXqq9z+YQudpCSCg== read-pkg-up@^1.0.1: version "1.0.1" @@ -6532,16 +5987,6 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -6627,11 +6072,6 @@ repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== -replace-ext@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" - integrity sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ== - replace-ext@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" @@ -6779,19 +6219,10 @@ saxes@^6.0.0: dependencies: xmlchars "^2.2.0" -scheduler@0.0.0-experimental-4beb1fd8-20241118: - version "0.0.0-experimental-4beb1fd8-20241118" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-4beb1fd8-20241118.tgz#3143baa23dfb4daed6a9d0bfd44a8050a0cdab93" - integrity sha512-b7GQktevD5BPcS+R5qY5se5oX4b8AHQyebWswGZBdLCmElIwR3Q+RO5EgsLOA4t5D3/TDjLm58CQG16uEB5rMA== - -schema-utils@^3.1.1, schema-utils@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" +scheduler@0.0.0-experimental-7670501b-20241124: + version "0.0.0-experimental-7670501b-20241124" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-7670501b-20241124.tgz#87eb07afd85a709b6cdff847cdf427ed4408830e" + integrity sha512-3gEk9E54G93Oio+DIwptiqdPQdhU28UYOOL4F5ktKEnkFuUdTme8CDcvPOmca5Hg9URhp1tNZnW8m6gP993YdQ== semver-greatest-satisfied-range@^1.1.0: version "1.1.0" @@ -6824,13 +6255,6 @@ semver@^7.5.3, semver@^7.5.4: dependencies: lru-cache "^6.0.0" -serialize-javascript@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" - integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== - dependencies: - randombytes "^2.1.0" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -6936,14 +6360,6 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-url@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" @@ -7107,11 +6523,6 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -7165,11 +6576,6 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -7184,7 +6590,7 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0, supports-color@^8.1.1: +supports-color@^8.0.0: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -7209,32 +6615,6 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -tapable@^2.1.1, tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -terser-webpack-plugin@^5.3.7: - version "5.3.9" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" - integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.17" - jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.1" - terser "^5.16.8" - -terser@^5.16.8: - version "5.22.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.22.0.tgz#4f18103f84c5c9437aafb7a14918273310a8a49d" - integrity sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -7273,11 +6653,6 @@ through2@^3.0.1: inherits "^2.0.4" readable-stream "2 || 3" -through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" @@ -7422,9 +6797,9 @@ typedarray@^0.0.6: integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== ua-parser-js@^0.7.30: - version "0.7.31" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" - integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== + version "0.7.40" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.40.tgz#c87d83b7bb25822ecfa6397a0da5903934ea1562" + integrity sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ== unbox-primitive@^1.0.2: version "1.0.2" @@ -7619,16 +6994,7 @@ vinyl-sourcemaps-apply@^0.2.0: dependencies: source-map "^0.5.1" -vinyl@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" - integrity sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA== - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^2.0.0, vinyl@^2.2.1: +vinyl@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974" integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw== @@ -7654,14 +7020,6 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -7672,55 +7030,6 @@ webidl-conversions@^7.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack-stream@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/webpack-stream/-/webpack-stream-7.0.0.tgz#e6a1edb9568198499af872678e95031752d72f00" - integrity sha512-XoAQTHyCaYMo6TS7Atv1HYhtmBgKiVLONJbzLBl2V3eibXQ2IT/MCRM841RW/r3vToKD5ivrTJFWgd/ghoxoRg== - dependencies: - fancy-log "^1.3.3" - lodash.clone "^4.3.2" - lodash.some "^4.2.2" - memory-fs "^0.5.0" - plugin-error "^1.0.1" - supports-color "^8.1.1" - through "^2.3.8" - vinyl "^2.2.1" - -webpack@^5.89.0: - version "5.89.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc" - integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== - dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.0" - "@webassemblyjs/ast" "^1.11.5" - "@webassemblyjs/wasm-edit" "^1.11.5" - "@webassemblyjs/wasm-parser" "^1.11.5" - acorn "^8.7.1" - acorn-import-assertions "^1.9.0" - browserslist "^4.14.5" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.15.0" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.2.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.7" - watchpack "^2.4.0" - webpack-sources "^3.2.3" - whatwg-encoding@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53"