From 9cdbf1146189527c83f39930cd235d8d56456d4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 18:14:40 +0000 Subject: [PATCH 01/40] Bump serde_json from 1.0.138 to 1.0.140 Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.138 to 1.0.140. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.138...v1.0.140) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 671ccaf..13feeac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ascii" @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", From 54014eaa6255500bb8d48e480aafd2028a414afe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 18:14:47 +0000 Subject: [PATCH 02/40] Bump proc-macro2 from 1.0.93 to 1.0.94 Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.93 to 1.0.94. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.93...1.0.94) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 6 +++--- shopify_function_macro/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 671ccaf..39eff41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ascii" @@ -148,9 +148,9 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index 876b0e2..3353dc9 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -12,6 +12,6 @@ proc-macro = true [dependencies] syn = { version = "1.0", features = ["full"] } quote = "1.0" -proc-macro2 = "1.0.93" +proc-macro2 = "1.0.94" convert_case = "0.7.1" graphql_client_codegen = "0.14.0" From 53b532fea00ab54fcfd0f3430a73d14aea9cdddb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:16:27 +0000 Subject: [PATCH 03/40] Bump convert_case from 0.7.1 to 0.8.0 Bumps [convert_case](https://github.com/rutrum/convert-case) from 0.7.1 to 0.8.0. - [Commits](https://github.com/rutrum/convert-case/commits) --- updated-dependencies: - dependency-name: convert_case dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- shopify_function_macro/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39eff41..504bc54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,9 +29,9 @@ dependencies = [ [[package]] name = "convert_case" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" dependencies = [ "unicode-segmentation", ] diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index 3353dc9..345274b 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -13,5 +13,5 @@ proc-macro = true syn = { version = "1.0", features = ["full"] } quote = "1.0" proc-macro2 = "1.0.94" -convert_case = "0.7.1" +convert_case = "0.8.0" graphql_client_codegen = "0.14.0" From 3388a7ab0f3ebd3ca891ea765e1605f6f5a2b4f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:16:39 +0000 Subject: [PATCH 04/40] Bump quote from 1.0.38 to 1.0.39 Bumps [quote](https://github.com/dtolnay/quote) from 1.0.38 to 1.0.39. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.38...1.0.39) --- updated-dependencies: - dependency-name: quote dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39eff41..364f6e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,9 +157,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" dependencies = [ "proc-macro2", ] From 0f26dbc6e413b33177c3fa90ba989323c9fd4580 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 19:00:00 +0000 Subject: [PATCH 05/40] Bump serde from 1.0.218 to 1.0.219 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.218 to 1.0.219. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.218...v1.0.219) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- example/Cargo.toml | 2 +- example_with_targets/Cargo.toml | 2 +- shopify_function/Cargo.toml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eca40bd..8119a5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,18 +172,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", diff --git a/example/Cargo.toml b/example/Cargo.toml index a5365f7..57e7789 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT" [dependencies] shopify_function = { path = "../shopify_function" } -serde = { version = "1.0.218", features = ["derive"] } +serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0" graphql_client = "0.14.0" graphql_client_codegen = "0.14.0" diff --git a/example_with_targets/Cargo.toml b/example_with_targets/Cargo.toml index 918e000..dffa7f0 100644 --- a/example_with_targets/Cargo.toml +++ b/example_with_targets/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT" [dependencies] shopify_function = { path = "../shopify_function" } -serde = { version = "1.0.218", features = ["derive"] } +serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0" graphql_client = "0.14.0" graphql_client_codegen = "0.14.0" diff --git a/shopify_function/Cargo.toml b/shopify_function/Cargo.toml index c758a04..8010246 100644 --- a/shopify_function/Cargo.toml +++ b/shopify_function/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" description = "Crate to write Shopify Functions in Rust." [dependencies] -serde = { version = "1.0.218", features = ["derive"] } +serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0" shopify_function_macro = { version = "0.8.1", path = "../shopify_function_macro" } From 09e6505a7c396f9ac9fbf953cfced8d0a9238c78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 19:00:06 +0000 Subject: [PATCH 06/40] Bump ryu from 1.0.18 to 1.0.20 Bumps [ryu](https://github.com/dtolnay/ryu) from 1.0.18 to 1.0.20. - [Release notes](https://github.com/dtolnay/ryu/releases) - [Commits](https://github.com/dtolnay/ryu/compare/1.0.18...1.0.20) --- updated-dependencies: - dependency-name: ryu dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eca40bd..5755a33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "serde" From e85c6e05684c13c2a8a12436ee1b4229a3b7974d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 19:13:26 +0000 Subject: [PATCH 07/40] Bump quote from 1.0.39 to 1.0.40 Bumps [quote](https://github.com/dtolnay/quote) from 1.0.39 to 1.0.40. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.39...1.0.40) --- updated-dependencies: - dependency-name: quote dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdeb2e9..61d16a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,9 +157,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] From 5f72741756ec92f8a67af84bbaa553d942d229d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 18:20:51 +0000 Subject: [PATCH 08/40] Bump proc-macro2 from 1.0.94 to 1.0.95 Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.94 to 1.0.95. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.94...1.0.95) --- updated-dependencies: - dependency-name: proc-macro2 dependency-version: 1.0.95 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- shopify_function_macro/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61d16a1..98f5dbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,9 +148,9 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index 345274b..d4193f1 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -12,6 +12,6 @@ proc-macro = true [dependencies] syn = { version = "1.0", features = ["full"] } quote = "1.0" -proc-macro2 = "1.0.94" +proc-macro2 = "1.0.95" convert_case = "0.8.0" graphql_client_codegen = "0.14.0" From 1f1f78897b264f3e03b35ceea1ccf080a64bb2eb Mon Sep 17 00:00:00 2001 From: Mehdi Salemi Date: Mon, 21 Apr 2025 14:39:59 -0400 Subject: [PATCH 09/40] clippy fix --- shopify_function_macro/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shopify_function_macro/src/lib.rs b/shopify_function_macro/src/lib.rs index d3e34e1..f46d46a 100644 --- a/shopify_function_macro/src/lib.rs +++ b/shopify_function_macro/src/lib.rs @@ -277,7 +277,7 @@ fn extract_shopify_function_return_type(ast: &syn::ItemFn) -> Result<&syn::Ident /// /// The macro takes the following parameters: /// - `query_path`: A path to a GraphQL query, whose result will be used -/// as the input for the function invocation. The query MUST be named "Input". +/// as the input for the function invocation. The query MUST be named "Input". /// - `schema_path`: A path to Shopify's GraphQL schema definition. Use the CLI /// to download a fresh copy. /// - `target` (optional): The API-specific handle for the target if the function name does not match the target handle as `snake_case` @@ -395,7 +395,7 @@ pub fn shopify_function_target( /// /// The macro takes the following parameters: /// - `query_path`: A path to a GraphQL query, whose result will be used -/// as the input for the function invocation. The query MUST be named "Input". +/// as the input for the function invocation. The query MUST be named "Input". /// - `schema_path`: A path to Shopify's GraphQL schema definition. Use the CLI /// to download a fresh copy. /// - `extern_enums` (optional): A list of Enums for which an external type should be used. From 7cd91b698bc1b92c61d4af5dc57945760cc0ab3a Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Tue, 29 Apr 2025 22:02:25 -0400 Subject: [PATCH 10/40] update github actions to commits --- .github/dependabot.yml | 4 ++++ .github/workflows/ci.yml | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3a9d3b7..b5d9409 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,9 @@ version: 2 updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly - package-ecosystem: "cargo" directory: "/" schedule: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1f39ba..8ae1d07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Add rustfmt and clippy run: rustup component add rustfmt clippy - name: Run cargo fmt @@ -26,13 +26,13 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Run tests run: cargo test build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Build run: cargo build --release From ade4fcabe1844bddbca9edec4a64f7553deb062c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 20:19:43 +0000 Subject: [PATCH 11/40] Bump actions/checkout from 3.6.0 to 4.2.2 Bumps [actions/checkout](https://github.com/actions/checkout) from 3.6.0 to 4.2.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/f43a0e5ff2bd294095638e18286ca9a3d1956744...11bd71901bbe5b1630ceea73d27597364c9af683) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 4.2.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ae1d07..ae7c80e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Add rustfmt and clippy run: rustup component add rustfmt clippy - name: Run cargo fmt @@ -26,13 +26,13 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run tests run: cargo test build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Build run: cargo build --release From 6a1a5206dffcc4b2b996012912eb1638661ea155 Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Wed, 30 Apr 2025 17:00:32 -0400 Subject: [PATCH 12/40] Add reviewers for github actions dependabots --- .github/dependabot.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b5d9409..2c6affb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,8 @@ updates: directory: "/" schedule: interval: weekly + reviewers: + - "@Shopify/functions-dependabot-reviewers" - package-ecosystem: "cargo" directory: "/" schedule: From 977af072a6bc21b8da9d88a79cf18b1adc81fe99 Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Fri, 16 May 2025 14:13:25 -0400 Subject: [PATCH 13/40] Support Wasm API (#130) Co-authored-by: Olivier Theriault --- .github/workflows/ci.yml | 2 - .gitignore | 1 + Cargo.lock | 1957 ++++++++- Cargo.toml | 2 +- README.md | 2 +- example/.output.graphql | 3 - example/Cargo.toml | 12 - example/README.md | 5 - example/input.graphql | 23 - example/schema.graphql | 3578 ----------------- example/src/main.rs | 70 - example/src/tests.rs | 112 - example_with_targets/Cargo.toml | 2 - example_with_targets/README.md | 125 +- example_with_targets/schema.graphql | 9 + example_with_targets/src/lib.rs | 31 - example_with_targets/src/main.rs | 35 + example_with_targets/src/tests.rs | 8 +- integration_tests/Cargo.toml | 10 + integration_tests/src/lib.rs | 216 + integration_tests/tests/integration_test.rs | 46 + rust-toolchain.toml | 4 + shopify_function/Cargo.toml | 6 +- shopify_function/README.md | 79 +- shopify_function/src/enums.rs | 3 - shopify_function/src/lib.rs | 31 +- shopify_function/src/scalars.rs | 15 +- shopify_function/src/scalars/decimal.rs | 55 +- shopify_function/src/scalars/json_value.rs | 169 + .../tests/derive_deserialize_test.rs | 35 + shopify_function/tests/fixtures/b.graphql | 4 - shopify_function/tests/fixtures/input.graphql | 6 - .../tests/fixtures/schema.graphql | 60 - .../fixtures/schema_with_targets.graphql | 78 - shopify_function/tests/generate_types.rs | 21 - shopify_function/tests/shopify_function.rs | 34 - .../tests/shopify_function_target.rs | 88 - shopify_function_macro/Cargo.toml | 9 +- shopify_function_macro/src/lib.rs | 1071 +++-- 39 files changed, 3086 insertions(+), 4931 deletions(-) delete mode 100644 example/.output.graphql delete mode 100644 example/Cargo.toml delete mode 100644 example/README.md delete mode 100644 example/input.graphql delete mode 100644 example/schema.graphql delete mode 100644 example/src/main.rs delete mode 100644 example/src/tests.rs delete mode 100644 example_with_targets/src/lib.rs create mode 100644 example_with_targets/src/main.rs create mode 100644 integration_tests/Cargo.toml create mode 100644 integration_tests/src/lib.rs create mode 100644 integration_tests/tests/integration_test.rs create mode 100644 rust-toolchain.toml delete mode 100644 shopify_function/src/enums.rs create mode 100644 shopify_function/src/scalars/json_value.rs create mode 100644 shopify_function/tests/derive_deserialize_test.rs delete mode 100644 shopify_function/tests/fixtures/b.graphql delete mode 100644 shopify_function/tests/fixtures/input.graphql delete mode 100644 shopify_function/tests/fixtures/schema.graphql delete mode 100644 shopify_function/tests/fixtures/schema_with_targets.graphql delete mode 100644 shopify_function/tests/generate_types.rs delete mode 100644 shopify_function/tests/shopify_function.rs delete mode 100644 shopify_function/tests/shopify_function_target.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae7c80e..062b5df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,8 +14,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Add rustfmt and clippy - run: rustup component add rustfmt clippy - name: Run cargo fmt run: cargo fmt --check - name: Run clippy diff --git a/.gitignore b/.gitignore index 72b17d2..9df4bf8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target shopify_function/*.output.graphql +tmp diff --git a/Cargo.lock b/Cargo.lock index 98f5dbc..f2c1d20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,10 +3,142 @@ version = 4 [[package]] -name = "ascii" -version = "0.9.3" +name = "addr2line" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "ariadne" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f5e3dca4e09a6f340a61a0e9c7b61e030c69fc27bf29d73218f7e5e3b7638f" +dependencies = [ + "unicode-width", + "yansi", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "bluejay-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5860a442543063d03e6f76795c268ea5679e91fac3500f10dba2feeb85cf1818" +dependencies = [ + "enum-as-inner", + "itertools", + "serde_json", + "strum", +] + +[[package]] +name = "bluejay-parser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e525e5fad12f700f107135151cb957f9e1ff8044cb52ba7562b76e6be2d34e5" +dependencies = [ + "ariadne", + "bluejay-core", + "enum-as-inner", + "itertools", + "logos", + "strum", +] + +[[package]] +name = "bluejay-typegen-codegen" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e8869859a2a7381c11caf6441b83813082c36275e7daf183c94b4a0ecdc30d" +dependencies = [ + "bluejay-core", + "bluejay-parser", + "bluejay-validator", + "convert_case", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bluejay-validator" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde85073f8756b2fa6bf18b52eef7d3b42414bd087bb75eb5ea0e4d9a2d10d95" +dependencies = [ + "bluejay-core", + "bluejay-parser", + "itertools", + "paste", + "seq-macro", + "serde_json", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" @@ -15,18 +147,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "combine" -version = "3.8.1" +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ - "ascii", - "byteorder", - "either", - "memchr", - "unreachable", + "shlex", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "convert_case" version = "0.8.0" @@ -36,6 +176,42 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.10.0" @@ -43,253 +219,1746 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] -name = "example" -version = "1.0.0" +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "graphql_client", - "graphql_client_codegen", - "serde", - "serde_json", - "shopify_function", + "cfg-if", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", ] [[package]] name = "example_with_targets" version = "1.0.0" dependencies = [ - "graphql_client", - "graphql_client_codegen", "serde", "serde_json", "shopify_function", ] [[package]] -name = "graphql-introspection-query" -version = "0.2.0" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2a4732cf5140bd6c082434494f785a19cfb566ab07d1382c3671f5812fed6d" -dependencies = [ - "serde", -] +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "graphql-parser" -version = "0.4.0" +name = "flate2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ebc8013b4426d5b81a4364c419a95ed0b404af2b82e2457de52d9348f0e474" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ - "combine", - "thiserror", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "graphql_client" -version = "0.14.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50cfdc7f34b7f01909d55c2dcb71d4c13cbcbb4a1605d6c8bd760d654c1144b" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "graphql_query_derive", - "serde", - "serde_json", + "foreign-types-shared", ] [[package]] -name = "graphql_client_codegen" -version = "0.14.0" +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e27ed0c2cf0c0cc52c6bcf3b45c907f433015e580879d14005386251842fb0a" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "graphql-introspection-query", - "graphql-parser", - "heck", - "lazy_static", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn 1.0.109", + "percent-encoding", ] [[package]] -name = "graphql_query_derive" -version = "0.14.0" +name = "futures-channel" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83febfa838f898cfa73dfaa7a8eb69ff3409021ac06ee94cfb3d622f6eeb1a97" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ - "graphql_client_codegen", - "proc-macro2", - "syn 1.0.109", + "futures-core", + "futures-sink", ] [[package]] -name = "heck" -version = "0.4.1" +name = "futures-core" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] -name = "itoa" -version = "1.0.10" +name = "futures-io" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "futures-sink" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] -name = "memchr" -version = "2.7.1" +name = "futures-task" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] -name = "proc-macro2" -version = "1.0.95" +name = "futures-util" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "unicode-ident", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", ] [[package]] -name = "quote" -version = "1.0.40" +name = "getrandom" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ - "proc-macro2", + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] -name = "ryu" -version = "1.0.20" +name = "getrandom" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] [[package]] -name = "serde" -version = "1.0.219" +name = "gimli" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" dependencies = [ - "serde_derive", + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "hashbrown" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.85", + "bytes", + "fnv", + "itoa", ] [[package]] -name = "serde_json" -version = "1.0.140" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", "itoa", - "memchr", - "ryu", - "serde", + "pin-project-lite", + "smallvec", + "tokio", + "want", ] [[package]] -name = "shopify_function" -version = "0.8.1" +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ - "graphql_client", - "graphql_client_codegen", - "ryu", - "serde", - "serde_json", - "shopify_function_macro", + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", ] [[package]] -name = "shopify_function_macro" -version = "0.8.1" +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "convert_case", - "graphql_client_codegen", - "proc-macro2", - "quote", - "syn 1.0.109", + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] -name = "syn" -version = "1.0.109" +name = "hyper-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] -name = "syn" -version = "2.0.85" +name = "icu_collections" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "displaydoc", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "thiserror" -version = "1.0.57" +name = "icu_locid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ - "thiserror-impl", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "thiserror-impl" -version = "1.0.57" +name = "icu_locid_transform" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.85", + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", ] [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "icu_locid_transform_data" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] -name = "unicode-segmentation" -version = "1.11.0" +name = "icu_normalizer" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] [[package]] -name = "unreachable" -version = "1.0.0" +name = "icu_normalizer_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" + +[[package]] +name = "icu_properties" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ - "void", + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", ] [[package]] -name = "void" -version = "1.0.2" +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[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 = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +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 = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "integration_tests" +version = "0.1.0" +dependencies = [ + "anyhow", + "flate2", + "reqwest", + "serde_json", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "logos" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab6f536c1af4c7cc81edf73da1f8029896e7e1e16a219ef09b184e76a296f3db" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189bbfd0b61330abea797e5e9276408f2edbe4f822d7ad08685d67419aafb34e" +dependencies = [ + "beef", + "fnv", + "lazy_static", + "proc-macro2", + "quote", + "regex-syntax", + "rustc_version", + "syn", +] + +[[package]] +name = "logos-derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebfe8e1a19049ddbfccbd14ac834b215e11b85b90bab0c2dba7c7b92fb5d5cba" +dependencies = [ + "logos-codegen", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shopify_function" +version = "0.8.1" +dependencies = [ + "ryu", + "serde_json", + "shopify_function_macro", + "shopify_function_wasm_api", +] + +[[package]] +name = "shopify_function_macro" +version = "0.8.1" +dependencies = [ + "bluejay-core", + "bluejay-typegen-codegen", + "convert_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shopify_function_provider" +version = "1.0.0" +source = "git+https://github.com/Shopify/shopify-function-wasm-api?rev=53b7f99c1cd67fc1f602495c745a9af166413573#53b7f99c1cd67fc1f602495c745a9af166413573" +dependencies = [ + "bumpalo", + "rmp", + "shopify_function_wasm_api_core", +] + +[[package]] +name = "shopify_function_wasm_api" +version = "0.0.1" +source = "git+https://github.com/Shopify/shopify-function-wasm-api?rev=53b7f99c1cd67fc1f602495c745a9af166413573#53b7f99c1cd67fc1f602495c745a9af166413573" +dependencies = [ + "rmp-serde", + "serde_json", + "shopify_function_provider", + "shopify_function_wasm_api_core", + "thiserror", +] + +[[package]] +name = "shopify_function_wasm_api_core" +version = "0.0.1" +source = "git+https://github.com/Shopify/shopify-function-wasm-api?rev=53b7f99c1cd67fc1f602495c745a9af166413573#53b7f99c1cd67fc1f602495c745a9af166413573" +dependencies = [ + "strum", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +dependencies = [ + "fastrand", + "getrandom 0.3.2", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.44.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[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 = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[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", +] + +[[package]] +name = "windows-sys" +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.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_i686_gnullvm 0.52.6", + "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", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yansi" +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", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[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 = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 770546e..b7d602f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [workspace] resolver = "2" members = [ - "example", "example_with_targets", "shopify_function", "shopify_function_macro", + "integration_tests", ] [profile.release] diff --git a/README.md b/README.md index af1a435..53319b1 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,4 @@ For documentation, please take a look at the [crate's docs.rs page][docs]. To se [crate]: https://crates.io/crates/shopify-function [docs]: https://docs.rs/shopify_function -[example]: https://github.com/Shopify/shopify-function-rust/tree/main/example \ No newline at end of file +[example]: https://github.com/Shopify/shopify-function-rust/tree/main/example_with_targets diff --git a/example/.output.graphql b/example/.output.graphql deleted file mode 100644 index cd95859..0000000 --- a/example/.output.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation Output($result: FunctionResult!) { - handleResult(result: $result) -} diff --git a/example/Cargo.toml b/example/Cargo.toml deleted file mode 100644 index 57e7789..0000000 --- a/example/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "example" -version = "1.0.0" -edition = "2021" -license = "MIT" - -[dependencies] -shopify_function = { path = "../shopify_function" } -serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0" -graphql_client = "0.14.0" -graphql_client_codegen = "0.14.0" diff --git a/example/README.md b/example/README.md deleted file mode 100644 index 0314b3e..0000000 --- a/example/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Shopify Rust function example - -This is an example of how to use the [Shopify Function Rust crate][crate] to write a Shopify Function. - -[crate]: https://crates.io/crates/shopify-function diff --git a/example/input.graphql b/example/input.graphql deleted file mode 100644 index dbe5644..0000000 --- a/example/input.graphql +++ /dev/null @@ -1,23 +0,0 @@ -query Input { - cart { - lines { - quantity - cost { - totalAmount { - amount - } - } - merchandise { - __typename - ...on ProductVariant { - id - } - } - } - } - discountNode { - metafield(namespace: "some-space", key: "function-config") { - value - } - } -} diff --git a/example/schema.graphql b/example/schema.graphql deleted file mode 100644 index b996aa2..0000000 --- a/example/schema.graphql +++ /dev/null @@ -1,3578 +0,0 @@ -schema { - query: Input - mutation: MutationRoot -} - -""" -Exactly one field of input must be provided, and all others omitted. -""" -directive @oneOf on INPUT_OBJECT - -""" -Represents a generic custom attribute. -""" -type Attribute { - """ - Key or name of the attribute. - """ - key: String! - - """ - Value of the attribute. - """ - value: String -} - -""" -Represents information about the buyer that is interacting with the cart. -""" -type BuyerIdentity { - """ - The customer associated with the cart. - """ - customer: Customer - - """ - The email address of the buyer that is interacting with the cart. - """ - email: String - - """ - The phone number of the buyer that is interacting with the cart. - """ - phone: String -} - -""" -A cart represents the merchandise that a buyer intends to purchase, and the cost associated with the cart. -""" -type Cart { - """ - The attributes associated with the cart. Attributes are represented as key-value pairs. - """ - attribute( - """ - The key of the attribute to retrieve. - """ - key: String - ): Attribute - - """ - Information about the buyer that is interacting with the cart. - """ - buyerIdentity: BuyerIdentity - - """ - The costs that the buyer will pay at checkout. - """ - cost: CartCost! - - """ - The delivery groups available for the cart based on the buyer's shipping address. - """ - deliveryGroups: [CartDeliveryGroup!]! - - """ - A list of lines containing information about the items the customer intends to purchase. - """ - lines: [CartLine!]! -} - -""" -The cost that the buyer will pay at checkout. -""" -type CartCost { - """ - The amount, before taxes and discounts, for the customer to pay. - """ - subtotalAmount: MoneyV2! - - """ - The total amount for the customer to pay. - """ - totalAmount: MoneyV2! - - """ - The duty amount for the customer to pay at checkout. - """ - totalDutyAmount: MoneyV2 - - """ - The tax amount for the customer to pay at checkout. - """ - totalTaxAmount: MoneyV2 -} - -""" -Information about the options available for one or more line items to be delivered to a specific address. -""" -type CartDeliveryGroup { - """ - A list of cart lines for the delivery group. - """ - cartLines: [CartLine!]! - - """ - The destination address for the delivery group. - """ - deliveryAddress: MailingAddress - - """ - The delivery options available for the delivery group. - """ - deliveryOptions: [CartDeliveryOption!]! - - """ - Unique identifier for the delivery group. - """ - id: ID! - - """ - Information about the delivery option the buyer has selected. - """ - selectedDeliveryOption: CartDeliveryOption -} - -""" -Information about a delivery option. -""" -type CartDeliveryOption { - """ - The code of the delivery option. - """ - code: String - - """ - The cost for the delivery option. - """ - cost: MoneyV2! - - """ - The method for the delivery option. - """ - deliveryMethodType: DeliveryMethod! - - """ - The description of the delivery option. - """ - description: String - - """ - The title of the delivery option. - """ - title: String -} - -""" -Represents information about the merchandise in the cart. -""" -type CartLine { - """ - Retrieve a cart line attribute by key. - - Cart line attributes are also known as line item properties in Liquid. - """ - attribute( - """ - The key of the attribute to retrieve. - """ - key: String - ): Attribute - - """ - The cost of the merchandise line that the buyer will pay at checkout. - """ - cost: CartLineCost! - - """ - The ID of the cart line. - """ - id: ID! - - """ - The merchandise that the buyer intends to purchase. - """ - merchandise: Merchandise! - - """ - The quantity of the merchandise that the customer intends to purchase. - """ - quantity: Int! -} - -""" -The cost of the merchandise line that the buyer will pay at checkout. -""" -type CartLineCost { - """ - The amount of the merchandise line. - """ - amountPerQuantity: MoneyV2! - - """ - The compare at amount of the merchandise line. - """ - compareAtAmountPerQuantity: MoneyV2 - - """ - The cost of the merchandise line before line-level discounts. - """ - subtotalAmount: MoneyV2! - - """ - The total cost of the merchandise line. - """ - totalAmount: MoneyV2! -} - -""" -A country. -""" -type Country { - """ - The ISO code of the country. - """ - isoCode: CountryCode! -} - -""" -The code designating a country/region, which generally follows ISO 3166-1 alpha-2 guidelines. -If a territory doesn't have a country code value in the `CountryCode` enum, then it might be considered a subdivision -of another country. For example, the territories associated with Spain are represented by the country code `ES`, -and the territories associated with the United States of America are represented by the country code `US`. -""" -enum CountryCode { - """ - Ascension Island. - """ - AC - - """ - Andorra. - """ - AD - - """ - United Arab Emirates. - """ - AE - - """ - Afghanistan. - """ - AF - - """ - Antigua & Barbuda. - """ - AG - - """ - Anguilla. - """ - AI - - """ - Albania. - """ - AL - - """ - Armenia. - """ - AM - - """ - Netherlands Antilles. - """ - AN - - """ - Angola. - """ - AO - - """ - Argentina. - """ - AR - - """ - Austria. - """ - AT - - """ - Australia. - """ - AU - - """ - Aruba. - """ - AW - - """ - Åland Islands. - """ - AX - - """ - Azerbaijan. - """ - AZ - - """ - Bosnia & Herzegovina. - """ - BA - - """ - Barbados. - """ - BB - - """ - Bangladesh. - """ - BD - - """ - Belgium. - """ - BE - - """ - Burkina Faso. - """ - BF - - """ - Bulgaria. - """ - BG - - """ - Bahrain. - """ - BH - - """ - Burundi. - """ - BI - - """ - Benin. - """ - BJ - - """ - St. Barthélemy. - """ - BL - - """ - Bermuda. - """ - BM - - """ - Brunei. - """ - BN - - """ - Bolivia. - """ - BO - - """ - Caribbean Netherlands. - """ - BQ - - """ - Brazil. - """ - BR - - """ - Bahamas. - """ - BS - - """ - Bhutan. - """ - BT - - """ - Bouvet Island. - """ - BV - - """ - Botswana. - """ - BW - - """ - Belarus. - """ - BY - - """ - Belize. - """ - BZ - - """ - Canada. - """ - CA - - """ - Cocos (Keeling) Islands. - """ - CC - - """ - Congo - Kinshasa. - """ - CD - - """ - Central African Republic. - """ - CF - - """ - Congo - Brazzaville. - """ - CG - - """ - Switzerland. - """ - CH - - """ - Côte d’Ivoire. - """ - CI - - """ - Cook Islands. - """ - CK - - """ - Chile. - """ - CL - - """ - Cameroon. - """ - CM - - """ - China. - """ - CN - - """ - Colombia. - """ - CO - - """ - Costa Rica. - """ - CR - - """ - Cuba. - """ - CU - - """ - Cape Verde. - """ - CV - - """ - Curaçao. - """ - CW - - """ - Christmas Island. - """ - CX - - """ - Cyprus. - """ - CY - - """ - Czechia. - """ - CZ - - """ - Germany. - """ - DE - - """ - Djibouti. - """ - DJ - - """ - Denmark. - """ - DK - - """ - Dominica. - """ - DM - - """ - Dominican Republic. - """ - DO - - """ - Algeria. - """ - DZ - - """ - Ecuador. - """ - EC - - """ - Estonia. - """ - EE - - """ - Egypt. - """ - EG - - """ - Western Sahara. - """ - EH - - """ - Eritrea. - """ - ER - - """ - Spain. - """ - ES - - """ - Ethiopia. - """ - ET - - """ - Finland. - """ - FI - - """ - Fiji. - """ - FJ - - """ - Falkland Islands. - """ - FK - - """ - Faroe Islands. - """ - FO - - """ - France. - """ - FR - - """ - Gabon. - """ - GA - - """ - United Kingdom. - """ - GB - - """ - Grenada. - """ - GD - - """ - Georgia. - """ - GE - - """ - French Guiana. - """ - GF - - """ - Guernsey. - """ - GG - - """ - Ghana. - """ - GH - - """ - Gibraltar. - """ - GI - - """ - Greenland. - """ - GL - - """ - Gambia. - """ - GM - - """ - Guinea. - """ - GN - - """ - Guadeloupe. - """ - GP - - """ - Equatorial Guinea. - """ - GQ - - """ - Greece. - """ - GR - - """ - South Georgia & South Sandwich Islands. - """ - GS - - """ - Guatemala. - """ - GT - - """ - Guinea-Bissau. - """ - GW - - """ - Guyana. - """ - GY - - """ - Hong Kong SAR. - """ - HK - - """ - Heard & McDonald Islands. - """ - HM - - """ - Honduras. - """ - HN - - """ - Croatia. - """ - HR - - """ - Haiti. - """ - HT - - """ - Hungary. - """ - HU - - """ - Indonesia. - """ - ID - - """ - Ireland. - """ - IE - - """ - Israel. - """ - IL - - """ - Isle of Man. - """ - IM - - """ - India. - """ - IN - - """ - British Indian Ocean Territory. - """ - IO - - """ - Iraq. - """ - IQ - - """ - Iran. - """ - IR - - """ - Iceland. - """ - IS - - """ - Italy. - """ - IT - - """ - Jersey. - """ - JE - - """ - Jamaica. - """ - JM - - """ - Jordan. - """ - JO - - """ - Japan. - """ - JP - - """ - Kenya. - """ - KE - - """ - Kyrgyzstan. - """ - KG - - """ - Cambodia. - """ - KH - - """ - Kiribati. - """ - KI - - """ - Comoros. - """ - KM - - """ - St. Kitts & Nevis. - """ - KN - - """ - North Korea. - """ - KP - - """ - South Korea. - """ - KR - - """ - Kuwait. - """ - KW - - """ - Cayman Islands. - """ - KY - - """ - Kazakhstan. - """ - KZ - - """ - Laos. - """ - LA - - """ - Lebanon. - """ - LB - - """ - St. Lucia. - """ - LC - - """ - Liechtenstein. - """ - LI - - """ - Sri Lanka. - """ - LK - - """ - Liberia. - """ - LR - - """ - Lesotho. - """ - LS - - """ - Lithuania. - """ - LT - - """ - Luxembourg. - """ - LU - - """ - Latvia. - """ - LV - - """ - Libya. - """ - LY - - """ - Morocco. - """ - MA - - """ - Monaco. - """ - MC - - """ - Moldova. - """ - MD - - """ - Montenegro. - """ - ME - - """ - St. Martin. - """ - MF - - """ - Madagascar. - """ - MG - - """ - North Macedonia. - """ - MK - - """ - Mali. - """ - ML - - """ - Myanmar (Burma). - """ - MM - - """ - Mongolia. - """ - MN - - """ - Macao SAR. - """ - MO - - """ - Martinique. - """ - MQ - - """ - Mauritania. - """ - MR - - """ - Montserrat. - """ - MS - - """ - Malta. - """ - MT - - """ - Mauritius. - """ - MU - - """ - Maldives. - """ - MV - - """ - Malawi. - """ - MW - - """ - Mexico. - """ - MX - - """ - Malaysia. - """ - MY - - """ - Mozambique. - """ - MZ - - """ - Namibia. - """ - NA - - """ - New Caledonia. - """ - NC - - """ - Niger. - """ - NE - - """ - Norfolk Island. - """ - NF - - """ - Nigeria. - """ - NG - - """ - Nicaragua. - """ - NI - - """ - Netherlands. - """ - NL - - """ - Norway. - """ - NO - - """ - Nepal. - """ - NP - - """ - Nauru. - """ - NR - - """ - Niue. - """ - NU - - """ - New Zealand. - """ - NZ - - """ - Oman. - """ - OM - - """ - Panama. - """ - PA - - """ - Peru. - """ - PE - - """ - French Polynesia. - """ - PF - - """ - Papua New Guinea. - """ - PG - - """ - Philippines. - """ - PH - - """ - Pakistan. - """ - PK - - """ - Poland. - """ - PL - - """ - St. Pierre & Miquelon. - """ - PM - - """ - Pitcairn Islands. - """ - PN - - """ - Palestinian Territories. - """ - PS - - """ - Portugal. - """ - PT - - """ - Paraguay. - """ - PY - - """ - Qatar. - """ - QA - - """ - Réunion. - """ - RE - - """ - Romania. - """ - RO - - """ - Serbia. - """ - RS - - """ - Russia. - """ - RU - - """ - Rwanda. - """ - RW - - """ - Saudi Arabia. - """ - SA - - """ - Solomon Islands. - """ - SB - - """ - Seychelles. - """ - SC - - """ - Sudan. - """ - SD - - """ - Sweden. - """ - SE - - """ - Singapore. - """ - SG - - """ - St. Helena. - """ - SH - - """ - Slovenia. - """ - SI - - """ - Svalbard & Jan Mayen. - """ - SJ - - """ - Slovakia. - """ - SK - - """ - Sierra Leone. - """ - SL - - """ - San Marino. - """ - SM - - """ - Senegal. - """ - SN - - """ - Somalia. - """ - SO - - """ - Suriname. - """ - SR - - """ - South Sudan. - """ - SS - - """ - São Tomé & Príncipe. - """ - ST - - """ - El Salvador. - """ - SV - - """ - Sint Maarten. - """ - SX - - """ - Syria. - """ - SY - - """ - Eswatini. - """ - SZ - - """ - Tristan da Cunha. - """ - TA - - """ - Turks & Caicos Islands. - """ - TC - - """ - Chad. - """ - TD - - """ - French Southern Territories. - """ - TF - - """ - Togo. - """ - TG - - """ - Thailand. - """ - TH - - """ - Tajikistan. - """ - TJ - - """ - Tokelau. - """ - TK - - """ - Timor-Leste. - """ - TL - - """ - Turkmenistan. - """ - TM - - """ - Tunisia. - """ - TN - - """ - Tonga. - """ - TO - - """ - Turkey. - """ - TR - - """ - Trinidad & Tobago. - """ - TT - - """ - Tuvalu. - """ - TV - - """ - Taiwan. - """ - TW - - """ - Tanzania. - """ - TZ - - """ - Ukraine. - """ - UA - - """ - Uganda. - """ - UG - - """ - U.S. Outlying Islands. - """ - UM - - """ - United States. - """ - US - - """ - Uruguay. - """ - UY - - """ - Uzbekistan. - """ - UZ - - """ - Vatican City. - """ - VA - - """ - St. Vincent & Grenadines. - """ - VC - - """ - Venezuela. - """ - VE - - """ - British Virgin Islands. - """ - VG - - """ - Vietnam. - """ - VN - - """ - Vanuatu. - """ - VU - - """ - Wallis & Futuna. - """ - WF - - """ - Samoa. - """ - WS - - """ - Kosovo. - """ - XK - - """ - Yemen. - """ - YE - - """ - Mayotte. - """ - YT - - """ - South Africa. - """ - ZA - - """ - Zambia. - """ - ZM - - """ - Zimbabwe. - """ - ZW - - """ - Unknown Region. - """ - ZZ -} - -""" -The three-letter currency codes that represent the world currencies used in -stores. These include standard ISO 4217 codes, legacy codes, -and non-standard codes. -""" -enum CurrencyCode { - """ - United Arab Emirates Dirham (AED). - """ - AED - - """ - Afghan Afghani (AFN). - """ - AFN - - """ - Albanian Lek (ALL). - """ - ALL - - """ - Armenian Dram (AMD). - """ - AMD - - """ - Netherlands Antillean Guilder. - """ - ANG - - """ - Angolan Kwanza (AOA). - """ - AOA - - """ - Argentine Pesos (ARS). - """ - ARS - - """ - Australian Dollars (AUD). - """ - AUD - - """ - Aruban Florin (AWG). - """ - AWG - - """ - Azerbaijani Manat (AZN). - """ - AZN - - """ - Bosnia and Herzegovina Convertible Mark (BAM). - """ - BAM - - """ - Barbadian Dollar (BBD). - """ - BBD - - """ - Bangladesh Taka (BDT). - """ - BDT - - """ - Bulgarian Lev (BGN). - """ - BGN - - """ - Bahraini Dinar (BHD). - """ - BHD - - """ - Burundian Franc (BIF). - """ - BIF - - """ - Bermudian Dollar (BMD). - """ - BMD - - """ - Brunei Dollar (BND). - """ - BND - - """ - Bolivian Boliviano (BOB). - """ - BOB - - """ - Brazilian Real (BRL). - """ - BRL - - """ - Bahamian Dollar (BSD). - """ - BSD - - """ - Bhutanese Ngultrum (BTN). - """ - BTN - - """ - Botswana Pula (BWP). - """ - BWP - - """ - Belarusian Ruble (BYN). - """ - BYN - - """ - Belarusian Ruble (BYR). - """ - BYR @deprecated(reason: "`BYR` is deprecated. Use `BYN` available from version `2021-01` onwards instead.") - - """ - Belize Dollar (BZD). - """ - BZD - - """ - Canadian Dollars (CAD). - """ - CAD - - """ - Congolese franc (CDF). - """ - CDF - - """ - Swiss Francs (CHF). - """ - CHF - - """ - Chilean Peso (CLP). - """ - CLP - - """ - Chinese Yuan Renminbi (CNY). - """ - CNY - - """ - Colombian Peso (COP). - """ - COP - - """ - Costa Rican Colones (CRC). - """ - CRC - - """ - Cape Verdean escudo (CVE). - """ - CVE - - """ - Czech Koruny (CZK). - """ - CZK - - """ - Djiboutian Franc (DJF). - """ - DJF - - """ - Danish Kroner (DKK). - """ - DKK - - """ - Dominican Peso (DOP). - """ - DOP - - """ - Algerian Dinar (DZD). - """ - DZD - - """ - Egyptian Pound (EGP). - """ - EGP - - """ - Eritrean Nakfa (ERN). - """ - ERN - - """ - Ethiopian Birr (ETB). - """ - ETB - - """ - Euro (EUR). - """ - EUR - - """ - Fijian Dollars (FJD). - """ - FJD - - """ - Falkland Islands Pounds (FKP). - """ - FKP - - """ - United Kingdom Pounds (GBP). - """ - GBP - - """ - Georgian Lari (GEL). - """ - GEL - - """ - Ghanaian Cedi (GHS). - """ - GHS - - """ - Gibraltar Pounds (GIP). - """ - GIP - - """ - Gambian Dalasi (GMD). - """ - GMD - - """ - Guinean Franc (GNF). - """ - GNF - - """ - Guatemalan Quetzal (GTQ). - """ - GTQ - - """ - Guyanese Dollar (GYD). - """ - GYD - - """ - Hong Kong Dollars (HKD). - """ - HKD - - """ - Honduran Lempira (HNL). - """ - HNL - - """ - Croatian Kuna (HRK). - """ - HRK - - """ - Haitian Gourde (HTG). - """ - HTG - - """ - Hungarian Forint (HUF). - """ - HUF - - """ - Indonesian Rupiah (IDR). - """ - IDR - - """ - Israeli New Shekel (NIS). - """ - ILS - - """ - Indian Rupees (INR). - """ - INR - - """ - Iraqi Dinar (IQD). - """ - IQD - - """ - Iranian Rial (IRR). - """ - IRR - - """ - Icelandic Kronur (ISK). - """ - ISK - - """ - Jersey Pound. - """ - JEP - - """ - Jamaican Dollars (JMD). - """ - JMD - - """ - Jordanian Dinar (JOD). - """ - JOD - - """ - Japanese Yen (JPY). - """ - JPY - - """ - Kenyan Shilling (KES). - """ - KES - - """ - Kyrgyzstani Som (KGS). - """ - KGS - - """ - Cambodian Riel. - """ - KHR - - """ - Kiribati Dollar (KID). - """ - KID - - """ - Comorian Franc (KMF). - """ - KMF - - """ - South Korean Won (KRW). - """ - KRW - - """ - Kuwaiti Dinar (KWD). - """ - KWD - - """ - Cayman Dollars (KYD). - """ - KYD - - """ - Kazakhstani Tenge (KZT). - """ - KZT - - """ - Laotian Kip (LAK). - """ - LAK - - """ - Lebanese Pounds (LBP). - """ - LBP - - """ - Sri Lankan Rupees (LKR). - """ - LKR - - """ - Liberian Dollar (LRD). - """ - LRD - - """ - Lesotho Loti (LSL). - """ - LSL - - """ - Lithuanian Litai (LTL). - """ - LTL - - """ - Latvian Lati (LVL). - """ - LVL - - """ - Libyan Dinar (LYD). - """ - LYD - - """ - Moroccan Dirham. - """ - MAD - - """ - Moldovan Leu (MDL). - """ - MDL - - """ - Malagasy Ariary (MGA). - """ - MGA - - """ - Macedonia Denar (MKD). - """ - MKD - - """ - Burmese Kyat (MMK). - """ - MMK - - """ - Mongolian Tugrik. - """ - MNT - - """ - Macanese Pataca (MOP). - """ - MOP - - """ - Mauritanian Ouguiya (MRU). - """ - MRU - - """ - Mauritian Rupee (MUR). - """ - MUR - - """ - Maldivian Rufiyaa (MVR). - """ - MVR - - """ - Malawian Kwacha (MWK). - """ - MWK - - """ - Mexican Pesos (MXN). - """ - MXN - - """ - Malaysian Ringgits (MYR). - """ - MYR - - """ - Mozambican Metical. - """ - MZN - - """ - Namibian Dollar. - """ - NAD - - """ - Nigerian Naira (NGN). - """ - NGN - - """ - Nicaraguan Córdoba (NIO). - """ - NIO - - """ - Norwegian Kroner (NOK). - """ - NOK - - """ - Nepalese Rupee (NPR). - """ - NPR - - """ - New Zealand Dollars (NZD). - """ - NZD - - """ - Omani Rial (OMR). - """ - OMR - - """ - Panamian Balboa (PAB). - """ - PAB - - """ - Peruvian Nuevo Sol (PEN). - """ - PEN - - """ - Papua New Guinean Kina (PGK). - """ - PGK - - """ - Philippine Peso (PHP). - """ - PHP - - """ - Pakistani Rupee (PKR). - """ - PKR - - """ - Polish Zlotych (PLN). - """ - PLN - - """ - Paraguayan Guarani (PYG). - """ - PYG - - """ - Qatari Rial (QAR). - """ - QAR - - """ - Romanian Lei (RON). - """ - RON - - """ - Serbian dinar (RSD). - """ - RSD - - """ - Russian Rubles (RUB). - """ - RUB - - """ - Rwandan Franc (RWF). - """ - RWF - - """ - Saudi Riyal (SAR). - """ - SAR - - """ - Solomon Islands Dollar (SBD). - """ - SBD - - """ - Seychellois Rupee (SCR). - """ - SCR - - """ - Sudanese Pound (SDG). - """ - SDG - - """ - Swedish Kronor (SEK). - """ - SEK - - """ - Singapore Dollars (SGD). - """ - SGD - - """ - Saint Helena Pounds (SHP). - """ - SHP - - """ - Sierra Leonean Leone (SLL). - """ - SLL - - """ - Somali Shilling (SOS). - """ - SOS - - """ - Surinamese Dollar (SRD). - """ - SRD - - """ - South Sudanese Pound (SSP). - """ - SSP - - """ - Sao Tome And Principe Dobra (STD). - """ - STD @deprecated(reason: "`STD` is deprecated. Use `STN` available from version `2022-07` onwards instead.") - - """ - Sao Tome And Principe Dobra (STN). - """ - STN - - """ - Syrian Pound (SYP). - """ - SYP - - """ - Swazi Lilangeni (SZL). - """ - SZL - - """ - Thai baht (THB). - """ - THB - - """ - Tajikistani Somoni (TJS). - """ - TJS - - """ - Turkmenistani Manat (TMT). - """ - TMT - - """ - Tunisian Dinar (TND). - """ - TND - - """ - Tongan Pa'anga (TOP). - """ - TOP - - """ - Turkish Lira (TRY). - """ - TRY - - """ - Trinidad and Tobago Dollars (TTD). - """ - TTD - - """ - Taiwan Dollars (TWD). - """ - TWD - - """ - Tanzanian Shilling (TZS). - """ - TZS - - """ - Ukrainian Hryvnia (UAH). - """ - UAH - - """ - Ugandan Shilling (UGX). - """ - UGX - - """ - United States Dollars (USD). - """ - USD - - """ - Uruguayan Pesos (UYU). - """ - UYU - - """ - Uzbekistan som (UZS). - """ - UZS - - """ - Venezuelan Bolivares (VED). - """ - VED - - """ - Venezuelan Bolivares (VEF). - """ - VEF @deprecated(reason: "`VEF` is deprecated. Use `VES` available from version `2020-10` onwards instead.") - - """ - Venezuelan Bolivares (VES). - """ - VES - - """ - Vietnamese đồng (VND). - """ - VND - - """ - Vanuatu Vatu (VUV). - """ - VUV - - """ - Samoan Tala (WST). - """ - WST - - """ - Central African CFA Franc (XAF). - """ - XAF - - """ - East Caribbean Dollar (XCD). - """ - XCD - - """ - West African CFA franc (XOF). - """ - XOF - - """ - CFP Franc (XPF). - """ - XPF - - """ - Unrecognized currency. - """ - XXX - - """ - Yemeni Rial (YER). - """ - YER - - """ - South African Rand (ZAR). - """ - ZAR - - """ - Zambian Kwacha (ZMW). - """ - ZMW -} - -""" -A custom product. -""" -type CustomProduct { - """ - Whether the merchandise is a gift card. - """ - isGiftCard: Boolean! - - """ - Whether the merchandise requires shipping. - """ - requiresShipping: Boolean! - - """ - The weight of the product variant in the unit system specified with `weight_unit`. - """ - weight: Float - - """ - Unit of measurement for weight. - """ - weightUnit: WeightUnit! -} - -""" -Represents a customer with the shop. -""" -type Customer implements HasMetafields { - """ - The total amount of money spent by the customer. Converted from the shop's - currency to the currency of the cart using a market rate. - """ - amountSpent: MoneyV2! - - """ - The customer’s name, email or phone number. - """ - displayName: String! - - """ - The customer’s email address. - """ - email: String - - """ - Whether the customer has any of the given tags. - """ - hasAnyTag( - """ - The tags to search for. - """ - tags: [String!]! = [] - ): Boolean! - - """ - A unique identifier for the customer. - """ - id: ID! - - """ - Returns a metafield by namespace and key that belongs to the resource. - """ - metafield( - """ - The key for the metafield. - """ - key: String! - - """ - The namespace for the metafield. - """ - namespace: String! - ): Metafield - - """ - The number of orders made by the customer. - """ - numberOfOrders: Int! -} - -""" -A signed decimal number, which supports arbitrary precision and is serialized as a string. - -Example values: `"29.99"`, `"29.999"`. -""" -scalar Decimal - -""" -List of different delivery method types. -""" -enum DeliveryMethod { - """ - Local Delivery. - """ - LOCAL - - """ - None. - """ - NONE - - """ - Shipping to a Pickup Point. - """ - PICKUP_POINT - - """ - Local Pickup. - """ - PICK_UP - - """ - Retail. - """ - RETAIL - - """ - Shipping. - """ - SHIPPING -} - -""" -The discount to be applied. -""" -input Discount { - """ - The discount message. - """ - message: String - - """ - The targets of the discount. - """ - targets: [Target!]! - - """ - The value of the discount. - """ - value: Value! -} - -""" -The strategy that's applied to the list of discounts. -""" -enum DiscountApplicationStrategy { - """ - Only apply the first discount with conditions that are satisfied. - """ - FIRST - - """ - Only apply the discount that offers the maximum reduction. - """ - MAXIMUM -} - -""" -A discount wrapper node. -""" -type DiscountNode implements HasMetafields { - """ - Returns a metafield by namespace and key that belongs to the resource. - """ - metafield( - """ - The key for the metafield. - """ - key: String! - - """ - The namespace for the metafield. - """ - namespace: String! - ): Metafield -} - -""" -A fixed amount value. -""" -input FixedAmount { - """ - The fixed amount value of the discount, in the currency of the cart. - - The amount must be greater than or equal to 0. - """ - amount: Decimal! - - """ - Whether to apply the value to each entitled item. - - The default value is `false`, which causes the value to be applied once across the entitled items. - When the value is `true`, the value will be applied to each of the entitled items. - """ - appliesToEachItem: Boolean -} - -""" -The result of the function. -""" -input FunctionResult { - """ - The strategy to apply the list of discounts. - """ - discountApplicationStrategy: DiscountApplicationStrategy! - - """ - The list of discounts to be applied. - """ - discounts: [Discount!]! -} - -""" -Represents information about the metafields associated to the specified resource. -""" -interface HasMetafields { - """ - Returns a metafield by namespace and key that belongs to the resource. - """ - metafield( - """ - The key for the metafield. - """ - key: String! - - """ - The namespace for the metafield. - """ - namespace: String! - ): Metafield -} - -""" -Represents a unique identifier, often used to refetch an object. -The ID type appears in a JSON response as a String, but it is not intended to be human-readable. - -Example value: `"gid://shopify/Product/10079785100"` -""" -scalar ID - -""" -The input object for the function. -""" -type Input { - """ - The cart to discount. - """ - cart: Cart! - - """ - The discount node executing the function. - """ - discountNode: DiscountNode! - - """ - The localization of the function execution context. - """ - localization: Localization! - - """ - The conversion rate between the shop's currency and the currency of the cart. - """ - presentmentCurrencyRate: Decimal! -} - -""" -A language. -""" -type Language { - """ - The ISO code. - """ - isoCode: LanguageCode! -} - -""" -ISO 639-1 language codes supported by Shopify. -""" -enum LanguageCode { - """ - Afrikaans. - """ - AF - - """ - Akan. - """ - AK - - """ - Amharic. - """ - AM - - """ - Arabic. - """ - AR - - """ - Assamese. - """ - AS - - """ - Azerbaijani. - """ - AZ - - """ - Belarusian. - """ - BE - - """ - Bulgarian. - """ - BG - - """ - Bambara. - """ - BM - - """ - Bangla. - """ - BN - - """ - Tibetan. - """ - BO - - """ - Breton. - """ - BR - - """ - Bosnian. - """ - BS - - """ - Catalan. - """ - CA - - """ - Chechen. - """ - CE - - """ - Czech. - """ - CS - - """ - Church Slavic. - """ - CU - - """ - Welsh. - """ - CY - - """ - Danish. - """ - DA - - """ - German. - """ - DE - - """ - Dzongkha. - """ - DZ - - """ - Ewe. - """ - EE - - """ - Greek. - """ - EL - - """ - English. - """ - EN - - """ - Esperanto. - """ - EO - - """ - Spanish. - """ - ES - - """ - Estonian. - """ - ET - - """ - Basque. - """ - EU - - """ - Persian. - """ - FA - - """ - Fulah. - """ - FF - - """ - Finnish. - """ - FI - - """ - Faroese. - """ - FO - - """ - French. - """ - FR - - """ - Western Frisian. - """ - FY - - """ - Irish. - """ - GA - - """ - Scottish Gaelic. - """ - GD - - """ - Galician. - """ - GL - - """ - Gujarati. - """ - GU - - """ - Manx. - """ - GV - - """ - Hausa. - """ - HA - - """ - Hebrew. - """ - HE - - """ - Hindi. - """ - HI - - """ - Croatian. - """ - HR - - """ - Hungarian. - """ - HU - - """ - Armenian. - """ - HY - - """ - Interlingua. - """ - IA - - """ - Indonesian. - """ - ID - - """ - Igbo. - """ - IG - - """ - Sichuan Yi. - """ - II - - """ - Icelandic. - """ - IS - - """ - Italian. - """ - IT - - """ - Japanese. - """ - JA - - """ - Javanese. - """ - JV - - """ - Georgian. - """ - KA - - """ - Kikuyu. - """ - KI - - """ - Kazakh. - """ - KK - - """ - Kalaallisut. - """ - KL - - """ - Khmer. - """ - KM - - """ - Kannada. - """ - KN - - """ - Korean. - """ - KO - - """ - Kashmiri. - """ - KS - - """ - Kurdish. - """ - KU - - """ - Cornish. - """ - KW - - """ - Kyrgyz. - """ - KY - - """ - Luxembourgish. - """ - LB - - """ - Ganda. - """ - LG - - """ - Lingala. - """ - LN - - """ - Lao. - """ - LO - - """ - Lithuanian. - """ - LT - - """ - Luba-Katanga. - """ - LU - - """ - Latvian. - """ - LV - - """ - Malagasy. - """ - MG - - """ - Māori. - """ - MI - - """ - Macedonian. - """ - MK - - """ - Malayalam. - """ - ML - - """ - Mongolian. - """ - MN - - """ - Marathi. - """ - MR - - """ - Malay. - """ - MS - - """ - Maltese. - """ - MT - - """ - Burmese. - """ - MY - - """ - Norwegian (Bokmål). - """ - NB - - """ - North Ndebele. - """ - ND - - """ - Nepali. - """ - NE - - """ - Dutch. - """ - NL - - """ - Norwegian Nynorsk. - """ - NN - - """ - Norwegian. - """ - NO - - """ - Oromo. - """ - OM - - """ - Odia. - """ - OR - - """ - Ossetic. - """ - OS - - """ - Punjabi. - """ - PA - - """ - Polish. - """ - PL - - """ - Pashto. - """ - PS - - """ - Portuguese. - """ - PT - - """ - Portuguese (Brazil). - """ - PT_BR - - """ - Portuguese (Portugal). - """ - PT_PT - - """ - Quechua. - """ - QU - - """ - Romansh. - """ - RM - - """ - Rundi. - """ - RN - - """ - Romanian. - """ - RO - - """ - Russian. - """ - RU - - """ - Kinyarwanda. - """ - RW - - """ - Sindhi. - """ - SD - - """ - Northern Sami. - """ - SE - - """ - Sango. - """ - SG - - """ - Sinhala. - """ - SI - - """ - Slovak. - """ - SK - - """ - Slovenian. - """ - SL - - """ - Shona. - """ - SN - - """ - Somali. - """ - SO - - """ - Albanian. - """ - SQ - - """ - Serbian. - """ - SR - - """ - Sundanese. - """ - SU - - """ - Swedish. - """ - SV - - """ - Swahili. - """ - SW - - """ - Tamil. - """ - TA - - """ - Telugu. - """ - TE - - """ - Tajik. - """ - TG - - """ - Thai. - """ - TH - - """ - Tigrinya. - """ - TI - - """ - Turkmen. - """ - TK - - """ - Tongan. - """ - TO - - """ - Turkish. - """ - TR - - """ - Tatar. - """ - TT - - """ - Uyghur. - """ - UG - - """ - Ukrainian. - """ - UK - - """ - Urdu. - """ - UR - - """ - Uzbek. - """ - UZ - - """ - Vietnamese. - """ - VI - - """ - Volapük. - """ - VO - - """ - Wolof. - """ - WO - - """ - Xhosa. - """ - XH - - """ - Yiddish. - """ - YI - - """ - Yoruba. - """ - YO - - """ - Chinese. - """ - ZH - - """ - Chinese (Simplified). - """ - ZH_CN - - """ - Chinese (Traditional). - """ - ZH_TW - - """ - Zulu. - """ - ZU -} - -""" -Information about the localized experiences configured for the shop. -""" -type Localization { - """ - The country of the active localized experience. - """ - country: Country! - - """ - The language of the active localized experience. - """ - language: Language! -} - -""" -Represents a mailing address. -""" -type MailingAddress { - """ - The first line of the address. Typically the street address or PO Box number. - """ - address1: String - - """ - The second line of the address. Typically the number of the apartment, suite, or unit. - """ - address2: String - - """ - The name of the city, district, village, or town. - """ - city: String - - """ - The name of the customer's company or organization. - """ - company: String - - """ - The two-letter code for the country of the address. For example, US. - """ - countryCode: CountryCode - - """ - The first name of the customer. - """ - firstName: String - - """ - The last name of the customer. - """ - lastName: String - - """ - The full name of the customer, based on firstName and lastName. - """ - name: String - - """ - A unique phone number for the customer. Formatted using E.164 standard. For example, +16135551111. - """ - phone: String - - """ - The two-letter code for the region. For example, ON. - """ - provinceCode: String - - """ - The zip or postal code of the address. - """ - zip: String -} - -""" -The merchandise to be purchased at checkout. -""" -union Merchandise = CustomProduct | ProductVariant - -""" -[Metafields](https://shopify.dev/apps/metafields) -enable you to attach additional information to a -Shopify resource, such as a [Product](https://shopify.dev/api/admin-graphql/latest/objects/product) -or a [Collection](https://shopify.dev/api/admin-graphql/latest/objects/collection). -For more information about the Shopify resources that you can attach metafields to, refer to -[HasMetafields](https://shopify.dev/api/admin/graphql/reference/common-objects/HasMetafields). -""" -type Metafield { - """ - The type of data that the metafield stores in the `value` field. - Refer to the list of [supported types](https://shopify.dev/apps/metafields/types). - """ - type: String! - - """ - The data to store in the metafield. The data is always stored as a string, regardless of the metafield's type. - """ - value: String! -} - -""" -A monetary value with currency. -""" -type MoneyV2 { - """ - Decimal money amount. - """ - amount: Decimal! - - """ - Currency of the money. - """ - currencyCode: CurrencyCode! -} - -""" -The root mutation for the API. -""" -type MutationRoot { - """ - Handles the function result. - """ - handleResult( - """ - The result of the function. - """ - result: FunctionResult! - ): Void! -} - -""" -A percentage value. -""" -input Percentage { - """ - The percentage value. - - The value is validated against: >= 0. - """ - value: Decimal! -} - -""" -Represents a product. -""" -type Product implements HasMetafields { - """ - A unique human-friendly string of the product's title. - """ - handle: String! - - """ - Whether the product has any of the given tags. - """ - hasAnyTag( - """ - The tags to search for. - """ - tags: [String!]! = [] - ): Boolean! - - """ - A globally-unique identifier. - """ - id: ID! - - """ - Whether the product has any of the given collection. - """ - inAnyCollection( - """ - The collections to search for. - """ - ids: [ID!]! = [] - ): Boolean! - - """ - Whether the product is a gift card. - """ - isGiftCard: Boolean! - - """ - Returns a metafield by namespace and key that belongs to the resource. - """ - metafield( - """ - The key for the metafield. - """ - key: String! - - """ - The namespace for the metafield. - """ - namespace: String! - ): Metafield - - """ - The product type specified by the merchant. - """ - productType: String - - """ - The name of the product's vendor. - """ - vendor: String -} - -""" -Represents a product variant. -""" -type ProductVariant implements HasMetafields { - """ - A globally-unique identifier. - """ - id: ID! - - """ - Returns a metafield by namespace and key that belongs to the resource. - """ - metafield( - """ - The key for the metafield. - """ - key: String! - - """ - The namespace for the metafield. - """ - namespace: String! - ): Metafield - - """ - The product that this variant belongs to. - """ - product: Product! - - """ - Whether the merchandise requires shipping. - """ - requiresShipping: Boolean! - - """ - An identifier for the product variant in the shop. Required in order to connect to a fulfillment service. - """ - sku: String - - """ - The weight of the product variant in the unit system specified with `weight_unit`. - """ - weight: Float - - """ - Unit of measurement for weight. - """ - weightUnit: WeightUnit! -} - -""" -The target product variant. -""" -input ProductVariantTarget { - """ - The ID of the target product variant. - """ - id: ID! - - """ - The number of line items that are being discounted. - The default value is `null`, which represents the quantity of the matching line items. - - The value is validated against: > 0. - """ - quantity: Int -} - -""" -The target of the discount. -""" -input Target @oneOf { - """ - The target product variant. - """ - productVariant: ProductVariantTarget -} - -""" -The value of the discount. -""" -input Value @oneOf { - """ - A fixed amount value. - """ - fixedAmount: FixedAmount - - """ - A percentage value. - """ - percentage: Percentage -} - -""" -A void type that can be used to return a null value from a mutation. -""" -scalar Void - -""" -Units of measurement for weight. -""" -enum WeightUnit { - """ - Metric system unit of mass. - """ - GRAMS - - """ - 1 kilogram equals 1000 grams. - """ - KILOGRAMS - - """ - Imperial system unit of mass. - """ - OUNCES - - """ - 1 pound equals 16 ounces. - """ - POUNDS -} diff --git a/example/src/main.rs b/example/src/main.rs deleted file mode 100644 index 78f2e0c..0000000 --- a/example/src/main.rs +++ /dev/null @@ -1,70 +0,0 @@ -use shopify_function::prelude::*; -use shopify_function::Result; - -use serde::{Deserialize, Serialize}; - -generate_types!( - query_path = "./input.graphql", - schema_path = "./schema.graphql" -); - -#[derive(Serialize, Deserialize, Default, PartialEq)] -struct Config { - pub quantity: i64, - pub percentage: f64, -} - -#[shopify_function] -fn function(input: input::ResponseData) -> Result { - let config: Config = input - .discount_node - .metafield - .as_ref() - .map(|m| serde_json::from_str::(m.value.as_str())) - .transpose()? - .unwrap_or_default(); - - let cart_lines = input.cart.lines; - - if cart_lines.is_empty() || config.percentage == 0.0 { - return Ok(output::FunctionResult { - discount_application_strategy: output::DiscountApplicationStrategy::FIRST, - discounts: vec![], - }); - } - - let mut targets = vec![]; - for line in cart_lines { - if line.quantity >= config.quantity { - targets.push(output::Target::ProductVariant( - output::ProductVariantTarget { - id: match line.merchandise { - input::InputCartLinesMerchandise::ProductVariant(variant) => variant.id, - _ => continue, - }, - quantity: None, - }, - )); - } - } - - if targets.is_empty() { - return Ok(output::FunctionResult { - discount_application_strategy: output::DiscountApplicationStrategy::FIRST, - discounts: vec![], - }); - } - Ok(output::FunctionResult { - discounts: vec![output::Discount { - message: None, - targets, - value: output::Value::Percentage(output::Percentage { - value: Decimal(config.percentage), - }), - }], - discount_application_strategy: output::DiscountApplicationStrategy::FIRST, - }) -} - -#[cfg(test)] -mod tests; diff --git a/example/src/tests.rs b/example/src/tests.rs deleted file mode 100644 index 6de906b..0000000 --- a/example/src/tests.rs +++ /dev/null @@ -1,112 +0,0 @@ -use super::*; -use shopify_function::{run_function_with_input, Result}; - -#[test] -fn test_discount_with_no_configuration() -> Result<()> { - let result = run_function_with_input( - function, - r#" - { - "cart": { - "lines": [ - { - "cost": { - "totalAmount": { - "amount": "0" - } - }, - "merchandise": { - "__typename": "ProductVariant", - "id": "gid://shopify/ProductVariant/0" - }, - "quantity": 5 - }, - { - "cost": { - "totalAmount": { - "amount": "0" - } - }, - "merchandise": { - "__typename": "ProductVariant", - "id": "gid://shopify/ProductVariant/1" - }, - "quantity": 1 - } - ] - }, - "discountNode": { - "metafield": null - } - } - "#, - )?; - let expected = crate::output::FunctionResult { - discounts: vec![], - discount_application_strategy: crate::output::DiscountApplicationStrategy::FIRST, - }; - assert_eq!(result, expected); - Ok(()) -} - -#[test] -fn test_discount_with_configuration() -> Result<()> { - let result = run_function_with_input( - function, - r#" - { - "cart": { - "lines": [ - { - "cost": { - "totalAmount": { - "amount": "0" - } - }, - "merchandise": { - "__typename": "ProductVariant", - "id": "gid://shopify/ProductVariant/0" - }, - "quantity": 5 - }, - { - "cost": { - "totalAmount": { - "amount": "10" - } - }, - "merchandise": { - "__typename": "ProductVariant", - "id": "gid://shopify/ProductVariant/1" - }, - "quantity": 1 - } - ] - }, - "discountNode": { - "metafield": { - "value": "{\"quantity\": 5, \"percentage\": 10}" - } - } - } - "#, - )?; - let expected = crate::output::FunctionResult { - discounts: vec![crate::output::Discount { - message: None, - targets: vec![crate::output::Target::ProductVariant( - output::ProductVariantTarget { - id: "gid://shopify/ProductVariant/0".to_string(), - quantity: None, - }, - )], - value: crate::output::Value::Percentage(output::Percentage { - value: Decimal(10.0), - }), - }], - discount_application_strategy: crate::output::DiscountApplicationStrategy::FIRST, - }; - - assert_eq!(result, expected); - Ok(()) -} diff --git a/example_with_targets/Cargo.toml b/example_with_targets/Cargo.toml index dffa7f0..f7795dc 100644 --- a/example_with_targets/Cargo.toml +++ b/example_with_targets/Cargo.toml @@ -8,5 +8,3 @@ license = "MIT" shopify_function = { path = "../shopify_function" } serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0" -graphql_client = "0.14.0" -graphql_client_codegen = "0.14.0" diff --git a/example_with_targets/README.md b/example_with_targets/README.md index 14fd75e..7def4b6 100644 --- a/example_with_targets/README.md +++ b/example_with_targets/README.md @@ -1,6 +1,6 @@ # Shopify Rust function example with targets -This is an example of how to use the [Shopify Function Rust crate][crate] with the `shopify_function_target` macro to write a Shopify Function with multiple API targets. +This is an example of how to use the [Shopify Function Rust crate][crate] with the `shopify_function` macro to write a Shopify Function with multiple API targets. ## Example API @@ -9,59 +9,6 @@ Target | Handle (`snake_case`) | GraphQL mutation `example.target-a` | `target_a` | `targetA(result: FunctionTargetAResult!)` `example.target-b` | `target_b` | `targetB(result: FunctionTargetBResult!)` -### `schema.graphql` - -```graphql -""" -The input object for the function. -""" -type Input { - id: ID! - num: Int - name: String - targetAResult: Int @restrictTarget(only: ["example.target-b"]) -} - -""" -The root mutation for the API. -""" -type MutationRoot { - """ - The function for API target A. - """ - targetA( - """ - The result of calling the function for API target A. - """ - result: FunctionTargetAResult! - ): Void! - - """ - The function for API target B. - """ - targetB( - """ - The result of calling the function for API target B. - """ - result: FunctionTargetBResult! - ): Void! -} - -""" -The result of API target A. -""" -input FunctionTargetAResult { - status: Int -} - -""" -The result of API target B. -""" -input FunctionTargetBResult { - name: String -} -``` - ## `shopify.function.extension.toml` ```toml @@ -81,74 +28,8 @@ export = "function_b" - `export` (optional): The name of the Wasm function export to run. - default: The target handle as `snake_case`. -## `shopify_function_target` usage - -### Arguments - -- `query_path`: A path to a GraphQL query, whose result will be used - as the input for the function invocation. The query MUST be named "Input". -- `schema_path`: A path to Shopify's GraphQL schema definition. Use the CLI - to download a fresh copy. -- `target` (optional): The API-specific handle for the target if the function name does not match the target handle as `snake_case`. -- `module_name` (optional): The name of the generated module. - - default: The target handle as `snake_case` -- `extern_enums` (optional): A list of Enums for which an external type should be used. - For those, code generation will be skipped. This is useful for large enums - which can increase binary size, or for enums shared between multiple targets. - Example: `extern_enums = ["LanguageCode"]` - - default: `["LanguageCode", "CountryCode", "CurrencyCode"]` - -### `src/lib.rs` - -```rust -#[shopify_function_target( - // Implicit target = "example.target-a" - // Implicit generated module name = "target_a" - query_path = "a.graphql", - schema_path = "schema.graphql" -)] -fn target_a( - _input: target_a::input::ResponseData, -) -> Result { - Ok(target_a::output::FunctionTargetAResult { status: Some(200) }) -} - -#[shopify_function_target( - // Explicit target if function name does not match target handle - target = "example.target-b", - // Override generated module name - module_name = "mod_b", - query_path = "b.graphql", - schema_path = "schema.graphql" -)] -fn function_b(input: mod_b::input::ResponseData) -> Result { - Ok(mod_b::output::FunctionTargetBResult { - name: Some(format!("new name: \"{}\"", input.id)), - }) -} -``` - -### Generated code - -The `shopify_function_target` macro uses `generate_types` and `shopify_function` to generate a module (optionally using `module_name`) containing: - -- `input` - - `ResponseData` for the target-specific input query -- `output` - - a target-specific result type, e.g. `FunctionTargetAResult` -- `export`: The function exported to the Wasm module using the Rust function name, which must match the export specified for the target in `shopify.function.extension.toml` - -The generated types can be viewed using the instructions in the `shopify_function` crate `README`. - -#### `*.output.graphql` - -Each target will have an `.output.graphql` file prefixed with the target handle as `snake_case`. This file is used to generate the target-specific `output` types, and can be added to `.gitignore`. - -Target handle (`snake_case`) | Output file | GraphQL mutation --- | -- | -- -`target_a` | `.target_a.output.graphql` | `mutation Output($result: FunctionTargetAResult!) { targetA(result: $result) }` -`target_b` | `.target_b.output.graphql` | `mutation Output($result: FunctionTargetBResult!) { targetB(result: $result) }` +## Generated code -If the Rust function name does not match the target handle as `snake_case`, the `target` argument must be provided to `shopify_function_target` to generate the `output` types. +The `typegen` macro modifies a module to add all types for the schema, as well as any queries added within the module. See the `shopify_function` crate documentation for more details. [crate]: https://crates.io/crates/shopify-function diff --git a/example_with_targets/schema.graphql b/example_with_targets/schema.graphql index 2f74d51..32b9046 100644 --- a/example_with_targets/schema.graphql +++ b/example_with_targets/schema.graphql @@ -68,6 +68,7 @@ type Input { dateTimeWithoutTimezone: DateTimeWithoutTimezone timeWithoutTimezone: TimeWithoutTimezone targetAResult: Int @restrictTarget(only: ["test.target-b"]) + country: CountryCode } """ @@ -108,3 +109,11 @@ The result of API target B. input FunctionTargetBResult { name: String } + +""" +The country code for the function. +""" +enum CountryCode { + AC + CA +} diff --git a/example_with_targets/src/lib.rs b/example_with_targets/src/lib.rs deleted file mode 100644 index a87d78a..0000000 --- a/example_with_targets/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -use shopify_function::prelude::*; -use shopify_function::Result; - -#[shopify_function_target( - // Implicit target = "example.target-a" - // Implicit generated module name = "target_a" - query_path = "a.graphql", - schema_path = "schema.graphql" -)] -fn target_a( - _input: target_a::input::ResponseData, -) -> Result { - Ok(target_a::output::FunctionTargetAResult { status: Some(200) }) -} - -#[shopify_function_target( - // Explicit target if function name does not match target handle - target = "example.target-b", - // Override generated module name - module_name = "mod_b", - query_path = "b.graphql", - schema_path = "schema.graphql" -)] -fn function_b(input: mod_b::input::ResponseData) -> Result { - Ok(mod_b::output::FunctionTargetBResult { - name: Some(format!("new name: \"{}\"", input.id)), - }) -} - -#[cfg(test)] -mod tests; diff --git a/example_with_targets/src/main.rs b/example_with_targets/src/main.rs new file mode 100644 index 0000000..e1a6bb7 --- /dev/null +++ b/example_with_targets/src/main.rs @@ -0,0 +1,35 @@ +use shopify_function::prelude::*; +use shopify_function::Result; + +#[derive(Deserialize)] +#[shopify_function(rename_all = "camelCase")] +struct Configuration {} + +#[typegen("./schema.graphql", enums_as_str = ["CountryCode"])] +mod schema { + #[query("./a.graphql")] + pub mod target_a {} + + #[query("./b.graphql")] + pub mod target_b {} +} + +#[shopify_function] +fn target_a(_input: schema::target_a::Input) -> Result { + Ok(schema::FunctionTargetAResult { status: Some(200) }) +} + +#[shopify_function] +fn target_b(input: schema::target_b::Input) -> Result { + Ok(schema::FunctionTargetBResult { + name: Some(format!("new name: \"{}\"", input.id())), + }) +} + +fn main() { + eprintln!("Invoke a named import"); + std::process::exit(1); +} + +#[cfg(test)] +mod tests; diff --git a/example_with_targets/src/tests.rs b/example_with_targets/src/tests.rs index ae1772c..2dc866e 100644 --- a/example_with_targets/src/tests.rs +++ b/example_with_targets/src/tests.rs @@ -13,15 +13,15 @@ fn test_a() -> Result<()> { } "#, )?; - let expected = crate::target_a::output::FunctionTargetAResult { status: Some(200) }; + let expected = crate::schema::FunctionTargetAResult { status: Some(200) }; assert_eq!(result, expected); Ok(()) } #[test] -fn test_function_b() -> Result<()> { +fn test_target_b() -> Result<()> { let result = run_function_with_input( - function_b, + target_b, r#" { "id": "gid://shopify/Order/1234567890", @@ -29,7 +29,7 @@ fn test_function_b() -> Result<()> { } "#, )?; - let expected = crate::mod_b::output::FunctionTargetBResult { + let expected = crate::schema::FunctionTargetBResult { name: Some("new name: \"gid://shopify/Order/1234567890\"".to_string()), }; diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml new file mode 100644 index 0000000..80a48ee --- /dev/null +++ b/integration_tests/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "integration_tests" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" +reqwest = { version = "0.12", features = ["blocking"] } +flate2 = "1.1" +serde_json = "1.0" diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs new file mode 100644 index 0000000..c7beb98 --- /dev/null +++ b/integration_tests/src/lib.rs @@ -0,0 +1,216 @@ +use anyhow::Result; +use std::{ + io::{Read, Write}, + path::PathBuf, + process::Command, + sync::LazyLock, +}; + +const FUNCTION_RUNNER_VERSION: &str = "8.0.0"; +const TRAMPOLINE_VERSION: &str = "1.0.0"; + +fn workspace_root() -> std::path::PathBuf { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + std::path::PathBuf::from(manifest_dir).join("..") +} + +/// Builds the example to a `.wasm` file +fn build_example(name: &str) -> Result<()> { + let status = Command::new("cargo") + .args([ + "build", + "--release", + "--target", + "wasm32-wasip1", + "-p", + name, + ]) + .status()?; + if !status.success() { + anyhow::bail!(status); + } + Ok(()) +} + +static FUNCTION_RUNNER_PATH: LazyLock> = LazyLock::new(|| { + let path = workspace_root().join(format!("tmp/function-runner-{}", FUNCTION_RUNNER_VERSION)); + + if !path.exists() { + std::fs::create_dir_all(workspace_root().join("tmp"))?; + download_function_runner(&path)?; + } + + Ok(path) +}); + +static TRAMPOLINE_PATH: LazyLock> = LazyLock::new(|| { + let path = workspace_root().join(format!("tmp/trampoline-{}", TRAMPOLINE_VERSION)); + if !path.exists() { + std::fs::create_dir_all(workspace_root().join("tmp"))?; + download_trampoline(&path)?; + } + Ok(path) +}); + +fn download_function_runner(destination: &PathBuf) -> Result<()> { + download_from_github( + |target_arch, target_os| { + format!( + "https://github.com/Shopify/function-runner/releases/download/v{}/function-runner-{}-{}-v{}.gz", + FUNCTION_RUNNER_VERSION, target_arch, target_os, FUNCTION_RUNNER_VERSION, + ) + }, + destination, + ) +} + +fn download_trampoline(destination: &PathBuf) -> Result<()> { + download_from_github( + |target_arch, target_os| { + format!( + "https://github.com/Shopify/shopify-function-wasm-api/releases/download/shopify_function_trampoline/v{}/shopify-function-trampoline-{}-{}-v{}.gz", + TRAMPOLINE_VERSION, target_arch, target_os, TRAMPOLINE_VERSION, + ) + }, + destination, + ) +} + +/// Downloads a file from github and saves it to the given destination +/// +/// The url_builder is a function that takes the target_arch and target_os and returns the url +fn download_from_github( + url_builder: impl Fn(&str, &str) -> String, + destination: &PathBuf, +) -> Result<()> { + let target_os = if cfg!(target_os = "macos") { + "macos" + } else if cfg!(target_os = "linux") { + "linux" + } else if cfg!(target_os = "windows") { + "windows" + } else { + anyhow::bail!("Unsupported target OS"); + }; + + let target_arch = if cfg!(target_arch = "x86_64") { + "x86_64" + } else if cfg!(target_arch = "aarch64") { + "arm" + } else { + anyhow::bail!("Unsupported target architecture"); + }; + + let url = url_builder(target_arch, target_os); + + let response = reqwest::blocking::get(&url)?; + if !response.status().is_success() { + anyhow::bail!("Failed to download artifact: {}", response.status()); + } + let bytes = response.bytes()?; + let mut gz_decoder = flate2::read::GzDecoder::new(bytes.as_ref()); + let mut file = std::fs::File::create(destination)?; + std::io::copy(&mut gz_decoder, &mut file)?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = file.metadata()?.permissions(); + perms.set_mode(0o755); + file.set_permissions(perms)?; + } + + Ok(()) +} + +pub fn prepare_example(name: &str) -> Result { + build_example(name)?; + let wasm_path = workspace_root() + .join("target/wasm32-wasip1/release") + .join(format!("{}.wasm", name)); + let trampolined_path = workspace_root() + .join("target/wasm32-wasip1/release") + .join(format!("{}-trampolined.wasm", name)); + let trampoline_path = TRAMPOLINE_PATH + .as_ref() + .map_err(|e| anyhow::anyhow!("Failed to download trampoline: {}", e))?; + let status = Command::new(trampoline_path) + .args([ + "-i", + wasm_path + .to_str() + .expect("Failed to convert wasm path to string"), + "-o", + trampolined_path + .to_str() + .expect("Failed to convert wasm path to string"), + ]) + .status()?; + assert!(status.success()); + Ok(trampolined_path) +} + +pub fn run_example( + path: PathBuf, + export: &str, + input: serde_json::Value, +) -> Result { + let function_runner_path = FUNCTION_RUNNER_PATH + .as_ref() + .map_err(|e| anyhow::anyhow!("Failed to download function runner: {}", e))?; + let input_json = serde_json::to_string(&input)?; + let mut child = Command::new(function_runner_path) + .args([ + "--json", + "--function", + path.to_str().expect("Failed to convert path to string"), + "--export", + export, + ]) + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn()?; + + let mut stdin = child + .stdin + .take() + .ok_or_else(|| anyhow::anyhow!("Failed to open stdin"))?; + + std::thread::spawn(move || { + stdin + .write_all(input_json.as_bytes()) + .expect("Failed to write to stdin"); + }); + + let status = child.wait()?; + + let mut output = child + .stdout + .take() + .ok_or_else(|| anyhow::anyhow!("Failed to open stdout"))?; + let mut output_bytes = Vec::new(); + output.read_to_end(&mut output_bytes)?; + + let output: serde_json::Value = serde_json::from_slice(&output_bytes)?; + + if !status.success() { + let logs = output + .get("logs") + .ok_or_else(|| anyhow::anyhow!("No logs"))? + .as_str() + .ok_or_else(|| anyhow::anyhow!("Logs are not a string"))?; + + anyhow::bail!( + "Function runner returned non-zero exit code: {}, logs: {}", + status, + logs, + ); + } + + let output_json_str = output + .get("output") + .and_then(|o| o.get("humanized").and_then(|h| h.as_str())) + .ok_or_else(|| anyhow::anyhow!("No output"))?; + let output_json: serde_json::Value = serde_json::from_str(output_json_str)?; + Ok(output_json) +} diff --git a/integration_tests/tests/integration_test.rs b/integration_tests/tests/integration_test.rs new file mode 100644 index 0000000..cc322e3 --- /dev/null +++ b/integration_tests/tests/integration_test.rs @@ -0,0 +1,46 @@ +use anyhow::Result; +use integration_tests::{prepare_example, run_example}; +use std::{path::PathBuf, sync::LazyLock}; + +static EXAMPLE_WITH_TARGETS_RESULT: LazyLock> = + LazyLock::new(|| prepare_example("example_with_targets")); + +#[test] +fn test_example_with_targets_target_a() -> Result<()> { + let path = EXAMPLE_WITH_TARGETS_RESULT + .as_ref() + .map_err(|e| anyhow::anyhow!("Failed to prepare example: {}", e))?; + let input = serde_json::json!({ + "id": "gid://shopify/Order/1234567890", + "num": 123, + "name": "test", + "country": "CA" + }); + let output = run_example(path.clone(), "target_a", input)?; + assert_eq!( + output, + serde_json::json!({ + "status": 200 + }) + ); + Ok(()) +} + +#[test] +fn test_example_with_targets_target_b() -> Result<()> { + let path = EXAMPLE_WITH_TARGETS_RESULT + .as_ref() + .map_err(|e| anyhow::anyhow!("Failed to prepare example: {}", e))?; + let input = serde_json::json!({ + "id": "gid://shopify/Order/1234567890", + "targetAResult": 200 + }); + let output = run_example(path.clone(), "target_b", input)?; + assert_eq!( + output, + serde_json::json!({ + "name": "new name: \"gid://shopify/Order/1234567890\"" + }) + ); + Ok(()) +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..1a8ec07 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "stable" +components = ["rustfmt", "clippy"] +targets = ["wasm32-wasip1"] diff --git a/shopify_function/Cargo.toml b/shopify_function/Cargo.toml index 8010246..6f588da 100644 --- a/shopify_function/Cargo.toml +++ b/shopify_function/Cargo.toml @@ -7,16 +7,12 @@ license = "MIT" description = "Crate to write Shopify Functions in Rust." [dependencies] -serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0" shopify_function_macro = { version = "0.8.1", path = "../shopify_function_macro" } +shopify_function_wasm_api = { git = "https://github.com/Shopify/shopify-function-wasm-api", rev = "53b7f99c1cd67fc1f602495c745a9af166413573" } # Use the `small` feature of ryu (transitive dependency through serde_json) # to shave off ~9kb of the Wasm binary size. [dependencies.ryu] version = "1" features = ["small"] - -[dev-dependencies] -graphql_client = "0.14.0" -graphql_client_codegen = "0.14.0" diff --git a/shopify_function/README.md b/shopify_function/README.md index dae4a44..26a0180 100644 --- a/shopify_function/README.md +++ b/shopify_function/README.md @@ -2,65 +2,78 @@ A crate to help developers build [Shopify Functions]. -## Dependencies - -- Make sure you have `graphql_client` in your dependencies - - ``` - cargo add graphql_client@0.14.0 - ``` - ## Usage -- The [`generate_types`] macro allows you to generate structs based on your [input query]. It will also generate output/response types for the current Function API, based on the provided schema. -- The [`shopify_function`] attribute macro marks the following function as the entry point for a Shopify Function. It manages the Functions `STDIN` input parsing and `STDOUT` output serialization for you. +- The [`typegen`] macro allows you to generate structs based on your Function API (based on the provided GraphQL schema) and multiple [input queries][input query]. +- The [`shopify_function`] attribute macro marks the following function as the entry point for a Shopify Function. It manages the Functions input parsing and output serialization for you. - The [`run_function_with_input`] function is a utility for unit testing which allows you to quickly add new tests based on a given JSON input string. -See the [example] for details on usage, or use the following guide to convert an existing Rust-based function. - -## Updating an existing function to use `shopify_function` +See the [example_with_targets] for details on usage, or use the following guide to convert an existing Rust-based function. -1. `cargo add shopify_function` -1. `cargo add graphql_client@0.14.0` -1. Delete `src/api.rs`. -1. In `main.rs`: +## Updating an existing function using a version of `shopify_function` below `0.9.0` to use version `0.9.0` and above - 1. Add imports for `shopify_function`. + 1. In `main.rs`, add imports for `shopify_function`. ```rust use shopify_function::prelude::*; use shopify_function::Result; ``` - 1. Remove references to `mod api`. - 1. Add type generation, right under your imports. + 1. In `main.rs`, add type generation, right under your imports. Remove any references to the `generate_types!` macro. Replace `./input.graphql` with the location of your input query file (e.g. `src/run.graphql`). + + ```rust + #[typegen("./schema.graphql")] + pub mod schema { + #[query("./input.graphql")] + pub mod input {} + } + ``` + If your Function has multiple targets each with their own input query, add a nested module for each. For example: ```rust - generate_types!(query_path = "./input.graphql", schema_path = "./schema.graphql"); + #[typegen("./schema.graphql")] + pub mod schema { + #[query("src/target_a.graphql")] + pub mod target_a {} + + #[query("src/target_b.graphql")] + pub mod target_b {} + } ``` - 1. Remove the `main` function entirely. - 1. Attribute the `function` function with the `shopify_function` macro, and change its return type. + 1. In `main.rs`, ensure that you have a `main` function that returns an error indicating to invoke a named export: + + ```rust + fn main() { + eprintln!("Invoke a named import"); + std::process::exit(1); + } + ``` + + 1. Throughout all of your source files, replace any references to `#[shopify_function_target]` with the `shopify_function` macro, and change its return type. Typically, this is located in a file with a name equal to the target, e.g. `run.rs`. ```rust #[shopify_function] - fn function(input: input::ResponseData) -> Result { + fn run(input: schema::input::Input) -> Result { ``` 1. Update the types and fields utilized in the function to the new, auto-generated structs. For example: | Old | New | | --- | --- | - | `input::Input` | `input::ResponseData` | - | `input::Metafield` | `input::InputDiscountNodeMetafield` | - | `input::DiscountNode` | `input::InputDiscountNode` | - | `FunctionResult` | `output::FunctionResult` | - | `DiscountApplicationStrategy::First` | `output::DiscountApplicationStrategy::FIRST` | + | `input::ResponseData` | `schema::input::Input` | + | `input::InputDiscountNodeMetafield` | `schema::input::input::discount_node::Metafield` | + | `input::InputDiscountNode` | `schema::input::input::DiscountNode` | + | `output::FunctionRunResult` | `schema::FunctionRunResult` | + | `output::DiscountApplicationStrategy::FIRST` | `schema::DiscountApplicationStrategy::First` | -1. Add `.output.graphql` to your `.gitignore`. + If referencing generated types from a file other than `main.rs` where they are defined, you'll need to import the schema. For example in `run.rs` you would need to add: + ```rust + use crate::schema; + ``` ## Viewing the generated types -To preview the types generated by the `generate_types` macro, use the [`cargo doc`](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) command. +To preview the types generated by the `typegen` macro, use the [`cargo doc`](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) command. ```bash cargo doc --open @@ -73,8 +86,8 @@ You can also use the [cargo-expand](https://github.com/dtolnay/cargo-expand) cra License Apache-2.0 [Shopify Functions]: https://shopify.dev/api/functions -[`generate_types`]: https://docs.rs/shopify_function/latest/shopify_function/macro.generate_types.html +[`generate_types`]: https://docs.rs/shopify_function/latest/shopify_function/macro.typegen.html [input query]: https://shopify.dev/api/functions/input-output#input [`shopify_function`]: https://docs.rs/shopify_function/latest/shopify_function/attr.shopify_function.html [`run_function_with_input`]: https://docs.rs/shopify_function/latest/shopify_function/fn.run_function_with_input.html -[example]: https://github.com/Shopify/shopify-function-rust/tree/main/example +[example_with_targets]: https://github.com/Shopify/shopify-function-rust/tree/main/example_with_targets diff --git a/shopify_function/src/enums.rs b/shopify_function/src/enums.rs deleted file mode 100644 index 33ed864..0000000 --- a/shopify_function/src/enums.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub type CountryCode = String; -pub type CurrencyCode = String; -pub type LanguageCode = String; diff --git a/shopify_function/src/lib.rs b/shopify_function/src/lib.rs index 931f739..345022e 100644 --- a/shopify_function/src/lib.rs +++ b/shopify_function/src/lib.rs @@ -8,26 +8,25 @@ //! ```ignore //! use shopify_function::prelude::* //! -//! generate_types!(query_path = "./input.graphql", schema_path = "./schema.graphql"); +//! #[typegen("./schema.graphql")] +//! mod schema { +//! #[query("./input.graphql")] +//! pub mod input {} +//! } //! //! #[shopify_function] -//! fn function(input: input::ResponseData) -> Result { +//! fn run(input: schema::input::Input) -> Result { //! /* ... */ //! } //! ``` -pub use shopify_function_macro::{generate_types, shopify_function, shopify_function_target}; +pub use shopify_function_macro::{shopify_function, typegen, Deserialize}; -#[doc(hidden)] -pub mod enums; -/// Only used for struct generation. -#[doc(hidden)] pub mod scalars; pub mod prelude { - pub use crate::enums::*; pub use crate::scalars::*; - pub use shopify_function_macro::{generate_types, shopify_function, shopify_function_target}; + pub use shopify_function_macro::{shopify_function, typegen, Deserialize}; } pub type Result = std::result::Result>; @@ -35,16 +34,18 @@ pub type Result = std::result::Result>; /// Runs the given function `f` with the invocation payload, returning the /// deserialized output. This function is provided as a helper when writing /// tests. -pub fn run_function_with_input<'a, F, P: serde::Deserialize<'a>, O>( - f: F, - payload: &'a str, -) -> Result +#[cfg(not(target_family = "wasm"))] +pub fn run_function_with_input(f: F, payload: &str) -> Result where F: Fn(P) -> Result, { - let parsed_payload: P = serde_json::from_str(payload)?; - f(parsed_payload) + let parsed_json: serde_json::Value = serde_json::from_str(payload)?; + let context = wasm_api::Context::new_with_input(parsed_json); + let input = wasm_api::Deserialize::deserialize(&context.input_get().unwrap()).unwrap(); + f(input) } +pub use shopify_function_wasm_api as wasm_api; + #[cfg(test)] mod tests {} diff --git a/shopify_function/src/scalars.rs b/shopify_function/src/scalars.rs index 9774bc6..5fdf8e1 100644 --- a/shopify_function/src/scalars.rs +++ b/shopify_function/src/scalars.rs @@ -1,16 +1,5 @@ mod decimal; +mod json_value; -pub type Boolean = bool; -pub type Float = f64; -pub type Int = i64; -pub type ID = String; -pub type JSON = serde_json::Value; pub use decimal::Decimal; -pub type Void = (); -pub type URL = String; -pub type Handle = String; - -pub type Date = String; -pub type DateTime = String; -pub type DateTimeWithoutTimezone = String; -pub type TimeWithoutTimezone = String; +pub use json_value::JsonValue; diff --git a/shopify_function/src/scalars/decimal.rs b/shopify_function/src/scalars/decimal.rs index 9f08939..8eab097 100644 --- a/shopify_function/src/scalars/decimal.rs +++ b/shopify_function/src/scalars/decimal.rs @@ -1,12 +1,9 @@ -use serde::{Deserialize, Serialize}; use std::fmt; use std::ops::Deref; /// Convenience wrapper for converting between Shopify's `Decimal` scalar, which /// is serialized as a `String`, and Rust's `f64`. -#[derive(Deserialize, Serialize, Debug, PartialEq, Clone, Copy)] -#[serde(try_from = "String")] -#[serde(into = "String")] +#[derive(Debug, PartialEq, Clone, Copy)] pub struct Decimal(pub f64); impl Decimal { @@ -34,7 +31,9 @@ impl TryFrom for Decimal { type Error = &'static str; fn try_from(value: String) -> Result { - serde_json::from_str(value.as_str()) + value + .as_str() + .parse::() .map(Self) .map_err(|_| "Error parsing decimal: invalid float literal") } @@ -42,7 +41,7 @@ impl TryFrom for Decimal { impl From for String { fn from(value: Decimal) -> Self { - ryu::Buffer::new().format(value.0).to_string() + value.to_string() } } @@ -58,34 +57,52 @@ impl From for Decimal { } } +impl crate::wasm_api::Deserialize for Decimal { + fn deserialize(value: &crate::wasm_api::Value) -> Result { + let string_value: String = crate::wasm_api::Deserialize::deserialize(value)?; + Self::try_from(string_value).map_err(|_| crate::wasm_api::read::Error::InvalidType) + } +} + +impl crate::wasm_api::Serialize for Decimal { + fn serialize( + &self, + context: &mut crate::wasm_api::Context, + ) -> Result<(), crate::wasm_api::write::Error> { + crate::wasm_api::Serialize::serialize(self.to_string().as_str(), context) + } +} + #[cfg(test)] mod tests { use super::Decimal; + use crate::wasm_api::{Context, Deserialize, Serialize}; #[test] - fn test_json_deserialization() { + fn test_deserialization() { let decimal_value = serde_json::json!("123.4"); - let decimal: Decimal = - serde_json::from_value(decimal_value).expect("Error deserializing from JSON"); + let context = Context::new_with_input(decimal_value); + let value = context.input_get().expect("Error getting input"); + let decimal: Decimal = Decimal::deserialize(&value).expect("Error deserializing from JSON"); assert_eq!(123.4, decimal.as_f64()); } #[test] - fn test_json_deserialization_error() { + fn test_deserialization_error() { let decimal_value = serde_json::json!("123.4.5"); - let error = - serde_json::from_value::(decimal_value).expect_err("Expected an error"); - assert_eq!( - "Error parsing decimal: invalid float literal", - error.to_string() - ); + let context = Context::new_with_input(decimal_value); + let value = context.input_get().expect("Error getting input"); + let error = Decimal::deserialize(&value).expect_err("Expected an error"); + assert_eq!("Invalid type", error.to_string()); } #[test] - fn test_json_serialization() { + fn test_serialization() { let decimal = Decimal(123.4); - let json_value = serde_json::to_value(decimal).expect("Error serializing to JSON"); - assert_eq!(serde_json::json!("123.4"), json_value); + let mut context = Context::new_with_input(serde_json::json!({})); + decimal.serialize(&mut context).unwrap(); + let output = context.finalize_output_and_return().unwrap(); + assert_eq!(serde_json::json!("123.4"), output); } #[test] diff --git a/shopify_function/src/scalars/json_value.rs b/shopify_function/src/scalars/json_value.rs new file mode 100644 index 0000000..24e048a --- /dev/null +++ b/shopify_function/src/scalars/json_value.rs @@ -0,0 +1,169 @@ +use shopify_function_wasm_api::{ + read::Error as ReadError, write::Error as WriteError, Context, Deserialize, Serialize, Value, +}; +use std::collections::BTreeMap; + +#[derive(Debug, PartialEq, Clone)] +pub enum JsonValue { + Null, + String(String), + Number(f64), + Boolean(bool), + Object(BTreeMap), + Array(Vec), +} + +impl Deserialize for JsonValue { + fn deserialize(value: &Value) -> Result { + if value.is_null() { + Ok(Self::Null) + } else if let Some(b) = value.as_bool() { + Ok(Self::Boolean(b)) + } else if let Some(n) = value.as_number() { + Ok(Self::Number(n)) + } else if let Some(s) = value.as_string() { + Ok(Self::String(s)) + } else if let Some(array_len) = value.array_len() { + let mut array = Vec::with_capacity(array_len); + for i in 0..array_len { + let item = value.get_at_index(i); + array.push(Self::deserialize(&item)?); + } + Ok(Self::Array(array)) + } else if let Some(object_len) = value.obj_len() { + let mut object = BTreeMap::new(); + for i in 0..object_len { + let key = value + .get_obj_key_at_index(i) + .ok_or(ReadError::InvalidType)?; + let value = value.get_at_index(i); + object.insert(key.to_string(), Self::deserialize(&value)?); + } + Ok(Self::Object(object)) + } else { + Err(ReadError::InvalidType) + } + } +} + +impl Serialize for JsonValue { + fn serialize(&self, context: &mut Context) -> Result<(), WriteError> { + match self { + Self::Null => context.write_null(), + Self::String(s) => context.write_utf8_str(s), + Self::Number(n) => context.write_f64(*n), + Self::Boolean(b) => context.write_bool(*b), + Self::Object(o) => context.write_object( + |ctx| { + for (key, value) in o { + ctx.write_utf8_str(key)?; + value.serialize(ctx)?; + } + Ok(()) + }, + o.len(), + ), + Self::Array(a) => context.write_array( + |ctx| { + for value in a { + value.serialize(ctx)?; + } + Ok(()) + }, + a.len(), + ), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_deserialize() { + let json = serde_json::json!({ + "null": null, + "string": "string", + "number": 123, + "boolean": true, + "object": { + "key": "value" + }, + "array": [1, 2, 3] + }); + let context = Context::new_with_input(json); + let value = context.input_get().unwrap(); + let json_value = JsonValue::deserialize(&value).unwrap(); + assert_eq!( + json_value, + JsonValue::Object(BTreeMap::from([ + ("null".to_string(), JsonValue::Null), + ( + "string".to_string(), + JsonValue::String("string".to_string()) + ), + ("number".to_string(), JsonValue::Number(123.0)), + ("boolean".to_string(), JsonValue::Boolean(true)), + ( + "object".to_string(), + JsonValue::Object(BTreeMap::from([( + "key".to_string(), + JsonValue::String("value".to_string()) + )])) + ), + ( + "array".to_string(), + JsonValue::Array(vec![ + JsonValue::Number(1.0), + JsonValue::Number(2.0), + JsonValue::Number(3.0) + ]) + ) + ])) + ); + } + + #[test] + fn test_serialize() { + let kitchen_sink_value = JsonValue::Object(BTreeMap::from([ + ("null".to_string(), JsonValue::Null), + ( + "string".to_string(), + JsonValue::String("string".to_string()), + ), + ("number".to_string(), JsonValue::Number(123.0)), + ("boolean".to_string(), JsonValue::Boolean(true)), + ( + "object".to_string(), + JsonValue::Object(BTreeMap::from([( + "key".to_string(), + JsonValue::String("value".to_string()), + )])), + ), + ( + "array".to_string(), + JsonValue::Array(vec![ + JsonValue::Number(1.0), + JsonValue::Number(2.0), + JsonValue::Number(3.0), + ]), + ), + ])); + + let mut context = Context::new_with_input(serde_json::json!({})); + kitchen_sink_value.serialize(&mut context).unwrap(); + let output = context.finalize_output_and_return().unwrap(); + let expected = serde_json::json!({ + "null": null, + "string": "string", + "number": 123.0, + "boolean": true, + "object": { + "key": "value" + }, + "array": [1.0, 2.0, 3.0] + }); + assert_eq!(output, expected); + } +} diff --git a/shopify_function/tests/derive_deserialize_test.rs b/shopify_function/tests/derive_deserialize_test.rs new file mode 100644 index 0000000..559fc5d --- /dev/null +++ b/shopify_function/tests/derive_deserialize_test.rs @@ -0,0 +1,35 @@ +use shopify_function::prelude::*; +use shopify_function::wasm_api::Deserialize; + +#[derive(Deserialize, PartialEq, Debug)] +#[shopify_function(rename_all = "camelCase")] +struct TestStruct { + field_a: String, + field_b: i32, +} + +#[test] +fn test_derive_deserialize() { + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "fieldA": "test", + "fieldB": 1, + })); + let root_value = context.input_get().unwrap(); + + let input = TestStruct::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestStruct { + field_a: "test".to_string(), + field_b: 1 + } + ); +} + +#[test] +fn test_derive_deserialize_error() { + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({})); + let root_value = context.input_get().unwrap(); + + TestStruct::deserialize(&root_value).unwrap_err(); +} diff --git a/shopify_function/tests/fixtures/b.graphql b/shopify_function/tests/fixtures/b.graphql deleted file mode 100644 index d408852..0000000 --- a/shopify_function/tests/fixtures/b.graphql +++ /dev/null @@ -1,4 +0,0 @@ -query Input { - id - targetAResult -} diff --git a/shopify_function/tests/fixtures/input.graphql b/shopify_function/tests/fixtures/input.graphql deleted file mode 100644 index 1030dfa..0000000 --- a/shopify_function/tests/fixtures/input.graphql +++ /dev/null @@ -1,6 +0,0 @@ -query Input { - id - num - name - country -} diff --git a/shopify_function/tests/fixtures/schema.graphql b/shopify_function/tests/fixtures/schema.graphql deleted file mode 100644 index 24392be..0000000 --- a/shopify_function/tests/fixtures/schema.graphql +++ /dev/null @@ -1,60 +0,0 @@ -schema { - query: Input - mutation: MutationRoot -} - -""" -Exactly one field of input must be provided, and all others omitted. -""" -directive @oneOf on INPUT_OBJECT - -""" -Represents a unique identifier, often used to refetch an object. -The ID type appears in a JSON response as a String, but it is not intended to be human-readable. - -Example value: `"gid://shopify/Product/10079785100"` -""" -scalar ID - -""" -A void type that can be used to return a null value from a mutation. -""" -scalar Void - -""" -The input object for the function. -""" -type Input { - id: ID! - num: Int - name: String - country: CountryCode -} - -""" -The root mutation for the API. -""" -type MutationRoot { - """ - Handles the function result. - """ - handleResult( - """ - The result of the function. - """ - result: FunctionResult! - ): Void! -} - -""" -The result of the function. -""" -input FunctionResult { - name: String - country: CountryCode -} - -enum CountryCode { - AC - CA -} diff --git a/shopify_function/tests/fixtures/schema_with_targets.graphql b/shopify_function/tests/fixtures/schema_with_targets.graphql deleted file mode 100644 index 17c3ea5..0000000 --- a/shopify_function/tests/fixtures/schema_with_targets.graphql +++ /dev/null @@ -1,78 +0,0 @@ -schema { - query: Input - mutation: MutationRoot -} - -""" -Only allow the field to be queried when targeting one of the specified targets. -""" -directive @restrictTarget(only: [String!]!) on FIELD_DEFINITION - -""" -Represents a unique identifier, often used to refetch an object. -The ID type appears in a JSON response as a String, but it is not intended to be human-readable. - -Example value: `"gid://shopify/Product/10079785100"` -""" -scalar ID - -""" -A void type that can be used to return a null value from a mutation. -""" -scalar Void - -""" -The input object for the function. -""" -type Input { - id: ID! - num: Int - name: String - country: CountryCode, - targetAResult: Int @restrictTarget(only: ["test.target-b"]) -} - -""" -The root mutation for the API. -""" -type MutationRoot { - """ - The function for API target A. - """ - targetA( - """ - The result of calling the function for API target A. - """ - result: FunctionTargetAResult! - ): Void! - - """ - The function for API target B. - """ - targetB( - """ - The result of calling the function for API target B. - """ - result: FunctionTargetBResult! - ): Void! -} - -""" -The result of API target A. -""" -input FunctionTargetAResult { - status: Int -} - -""" -The result of API target B. -""" -input FunctionTargetBResult { - name: String - country: CountryCode -} - -enum CountryCode { - AC - CA -} diff --git a/shopify_function/tests/generate_types.rs b/shopify_function/tests/generate_types.rs deleted file mode 100644 index 137f605..0000000 --- a/shopify_function/tests/generate_types.rs +++ /dev/null @@ -1,21 +0,0 @@ -use shopify_function::prelude::*; - -generate_types!( - query_path = "./tests/fixtures/input.graphql", - schema_path = "./tests/fixtures/schema.graphql" -); - -#[test] -fn test_json_deserialization() { - let input = r#"{ - "id": "gid://shopify/Order/1234567890", - "num": 123, - "name": "test" - }"#; - - let parsed: input::ResponseData = serde_json::from_str(input).unwrap(); - - assert_eq!(parsed.id, "gid://shopify/Order/1234567890"); - assert_eq!(parsed.num, Some(123)); - assert_eq!(parsed.name, Some("test".to_string())); -} diff --git a/shopify_function/tests/shopify_function.rs b/shopify_function/tests/shopify_function.rs deleted file mode 100644 index 77969f9..0000000 --- a/shopify_function/tests/shopify_function.rs +++ /dev/null @@ -1,34 +0,0 @@ -use shopify_function::prelude::*; -use shopify_function::Result; - -const FUNCTION_INPUT: &str = r#"{ - "id": "gid://shopify/Order/1234567890", - "num": 123, - "name": "test", - "country": "CA" -}"#; -static mut FUNCTION_OUTPUT: Vec = vec![]; - -generate_types!( - query_path = "./tests/fixtures/input.graphql", - schema_path = "./tests/fixtures/schema.graphql" -); - -#[test] -fn test_function() { - let expected_result = r#"{"name":"new name: gid://shopify/Order/1234567890","country":"CA"}"#; - main().unwrap(); - let actual_result = std::str::from_utf8(unsafe { FUNCTION_OUTPUT.as_slice() }).unwrap(); - assert_eq!(actual_result, expected_result); -} - -#[shopify_function( - input_stream = std::io::Cursor::new(FUNCTION_INPUT.as_bytes().to_vec()), - output_stream = unsafe { &mut FUNCTION_OUTPUT } -)] -fn my_function(input: input::ResponseData) -> Result { - Ok(output::FunctionResult { - name: Some(format!("new name: {}", input.id)), - country: Some("CA".to_string()), - }) -} diff --git a/shopify_function/tests/shopify_function_target.rs b/shopify_function/tests/shopify_function_target.rs deleted file mode 100644 index e2c5eae..0000000 --- a/shopify_function/tests/shopify_function_target.rs +++ /dev/null @@ -1,88 +0,0 @@ -use shopify_function::prelude::*; -use shopify_function::Result; - -const TARGET_A_INPUT: &str = r#"{ - "id": "gid://shopify/Order/1234567890", - "num": 123, - "name": "test", - "country": "CA" -}"#; -static mut TARGET_A_OUTPUT: Vec = vec![]; - -#[test] -fn test_target_a_export() { - let expected_result = r#"{"status":200}"#; - target_a::export(); - let actual_result = std::str::from_utf8(unsafe { TARGET_A_OUTPUT.as_slice() }).unwrap(); - assert_eq!(actual_result, expected_result); -} - -#[shopify_function_target( - // Implicit target = "test.target-a" - query_path = "./tests/fixtures/input.graphql", - schema_path = "./tests/fixtures/schema_with_targets.graphql", - input_stream = std::io::Cursor::new(TARGET_A_INPUT.as_bytes().to_vec()), - output_stream = unsafe { &mut TARGET_A_OUTPUT } -)] -fn target_a( - input: target_a::input::ResponseData, -) -> Result { - if input.country != Some("CA".to_string()) { - panic!("Expected CountryCode to be the CA String") - } - Ok(target_a::output::FunctionTargetAResult { status: Some(200) }) -} - -const TARGET_B_INPUT: &str = r#"{ - "id": "gid://shopify/Order/1234567890", - "targetAResult": 200 -}"#; -static mut TARGET_B_OUTPUT: Vec = vec![]; - -#[test] -fn test_mod_b_export() { - let expected_result = r#"{"name":"new name: gid://shopify/Order/1234567890","country":"CA"}"#; - mod_b::export(); - let actual_result = std::str::from_utf8(unsafe { TARGET_B_OUTPUT.as_slice() }).unwrap(); - assert_eq!(actual_result, expected_result); -} - -#[shopify_function_target( - target = "test.target-b", - module_name = "mod_b", - query_path = "./tests/fixtures/b.graphql", - schema_path = "./tests/fixtures/schema_with_targets.graphql", - input_stream = std::io::Cursor::new(TARGET_B_INPUT.as_bytes().to_vec()), - output_stream = unsafe { &mut TARGET_B_OUTPUT }, -)] -fn some_function( - input: mod_b::input::ResponseData, -) -> Result { - Ok(mod_b::output::FunctionTargetBResult { - name: Some(format!("new name: {}", input.id)), - country: Some("CA".to_string()), - }) -} - -// Verify that the CountryCode enum is generated when `extern_enums = []` -#[shopify_function_target( - target = "test.target-a", - module_name = "country_enum", - query_path = "./tests/fixtures/input.graphql", - schema_path = "./tests/fixtures/schema_with_targets.graphql", - extern_enums = [] -)] -fn _with_generated_country_code( - input: country_enum::input::ResponseData, -) -> Result { - use country_enum::*; - - let status = match input.country { - Some(input::CountryCode::CA) => 200, - _ => 201, - }; - - Ok(output::FunctionTargetAResult { - status: Some(status), - }) -} diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index d4193f1..31053b6 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -10,8 +10,9 @@ description = "Macros for the `shopify_function` crate." proc-macro = true [dependencies] -syn = { version = "1.0", features = ["full"] } +syn = { version = "2.0", features = ["full"] } quote = "1.0" -proc-macro2 = "1.0.95" -convert_case = "0.8.0" -graphql_client_codegen = "0.14.0" +proc-macro2 = "1.0.94" +bluejay-typegen-codegen = "0.3.1" +bluejay-core = "0.3.1" +convert_case = "0.8" diff --git a/shopify_function_macro/src/lib.rs b/shopify_function_macro/src/lib.rs index f46d46a..c8adf30 100644 --- a/shopify_function_macro/src/lib.rs +++ b/shopify_function_macro/src/lib.rs @@ -1,223 +1,19 @@ -use convert_case::{Case, Casing}; -use graphql_client_codegen::{ - generate_module_token_stream_from_string, CodegenMode, GraphQLClientCodegenOptions, +use std::collections::HashMap; + +use bluejay_core::{ + definition::{ + EnumTypeDefinition, EnumValueDefinition, InputObjectTypeDefinition, InputValueDefinition, + }, + AsIter, }; -use std::path::Path; - -use proc_macro2::{Ident, Span, TokenStream}; -use quote::{quote, ToTokens}; -use syn::{ - self, - parse::{Parse, ParseStream}, - parse_macro_input, Expr, ExprArray, FnArg, LitStr, Token, +use bluejay_typegen_codegen::{ + generate_schema, names, CodeGenerator, ExecutableStruct, Input as BluejayInput, + KnownCustomScalarType, WrappedExecutableType, }; - -#[derive(Clone, Default)] -struct ShopifyFunctionArgs { - input_stream: Option, - output_stream: Option, -} - -impl ShopifyFunctionArgs { - fn parse_expression(input: &ParseStream<'_>) -> syn::Result { - input.parse::()?; - input.parse::()?; - let value: Expr = input.parse()?; - Ok(value) - } -} - -impl Parse for ShopifyFunctionArgs { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut args = Self::default(); - while !input.is_empty() { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::input_stream) { - args.input_stream = Some(Self::parse_expression::(&input)?); - } else if lookahead.peek(kw::output_stream) { - args.output_stream = Some(Self::parse_expression::(&input)?); - } else { - // Ignore unknown tokens - let _ = input.parse::(); - } - } - Ok(args) - } -} - -/// Marks a function as a Shopify Function entry point. -/// -/// This attribute marks the following function as the entry point -/// for a Shopify Function. A Shopify Function takes exactly one -/// parameter of type `input::ResponseData`, and returns a -/// `Result`. Both of these types are generated -/// at build time from the Shopify's GraphQL schema. Take a look at the -/// [`macro@generate_types`] macro for details on those types. -/// -/// ```ignore -/// #[shopify_function] -/// fn function(input: input::ResponseData) -> Result { -/// /* ... */ -/// } -/// ``` -/// -/// By default, the function input is read from stdin and the result -/// is outputted to stdout. To override this, optional `input_stream` -/// and `output_stream` parameters can be set. These parameters must -/// implement the std::io::Read and std::io::Write traits respectively. -/// -/// ```ignore -/// #[shopify_function(input_stream = MyInputStream, output_stream = MyOutputStream)] -/// fn function(input: input::ResponseData) -> Result { -/// /* ... */ -/// } -/// ``` -#[proc_macro_attribute] -pub fn shopify_function( - attr: proc_macro::TokenStream, - item: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - let ast = parse_macro_input!(item as syn::ItemFn); - let args = parse_macro_input!(attr as ShopifyFunctionArgs); - - let name = &ast.sig.ident; - if ast.sig.inputs.len() != 1 { - return quote! {compile_error!("Shopify functions need exactly one input parameter");} - .into(); - } - - let input_type = match &ast.sig.inputs.first().unwrap() { - FnArg::Typed(input) => input.ty.as_ref(), - FnArg::Receiver(_) => { - return quote! {compile_error!("Shopify functions can’t have a receiver");}.into() - } - }; - - let input_stream = args - .input_stream - .map_or(quote! { std::io::stdin() }, |stream| { - stream.to_token_stream() - }); - let output_stream = args - .output_stream - .map_or(quote! { std::io::stdout() }, |stream| { - stream.to_token_stream() - }); - - let gen = quote! { - fn main() -> ::shopify_function::Result<()> { - let mut string = String::new(); - std::io::Read::read_to_string(&mut #input_stream, &mut string)?; - let input: #input_type = serde_json::from_str(&string)?; - let mut out = #output_stream; - let result = #name(input)?; - let serialized = serde_json::to_vec(&result)?; - std::io::Write::write_all(&mut out, serialized.as_slice())?; - Ok(()) - } - #ast - }; - - gen.into() -} - -#[derive(Clone, Default)] -struct ShopifyFunctionTargetArgs { - target: Option, - module_name: Option, - query_path: Option, - schema_path: Option, - input_stream: Option, - output_stream: Option, - extern_enums: Option, -} - -impl ShopifyFunctionTargetArgs { - fn parse( - input: &ParseStream<'_>, - ) -> syn::Result { - input.parse::()?; - input.parse::()?; - let value: V = input.parse()?; - if input.lookahead1().peek(Token![,]) { - input.parse::()?; - } - Ok(value) - } -} - -impl Parse for ShopifyFunctionTargetArgs { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut args = Self::default(); - while !input.is_empty() { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::target) { - args.target = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::module_name) { - args.module_name = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::query_path) { - args.query_path = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::schema_path) { - args.schema_path = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::input_stream) { - args.input_stream = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::output_stream) { - args.output_stream = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::extern_enums) { - args.extern_enums = Some(Self::parse::(&input)?); - } else { - return Err(lookahead.error()); - } - } - Ok(args) - } -} - -#[derive(Clone, Default)] -struct GenerateTypeArgs { - query_path: Option, - schema_path: Option, - input_stream: Option, - output_stream: Option, - extern_enums: Option, -} - -impl GenerateTypeArgs { - fn parse( - input: &ParseStream<'_>, - ) -> syn::Result { - input.parse::()?; - input.parse::()?; - let value: V = input.parse()?; - if input.lookahead1().peek(Token![,]) { - input.parse::()?; - } - Ok(value) - } -} - -impl Parse for GenerateTypeArgs { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut args = Self::default(); - while !input.is_empty() { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::query_path) { - args.query_path = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::schema_path) { - args.schema_path = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::input_stream) { - args.input_stream = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::output_stream) { - args.output_stream = Some(Self::parse::(&input)?); - } else if lookahead.peek(kw::extern_enums) { - args.extern_enums = Some(Self::parse::(&input)?); - } else { - return Err(lookahead.error()); - } - } - Ok(args) - } -} +use convert_case::{Case, Casing}; +use proc_macro2::Span; +use quote::{format_ident, quote, ToTokens}; +use syn::{parse_macro_input, parse_quote, FnArg}; fn extract_shopify_function_return_type(ast: &syn::ItemFn) -> Result<&syn::Ident, syn::Error> { use syn::*; @@ -268,265 +64,664 @@ fn extract_shopify_function_return_type(ast: &syn::ItemFn) -> Result<&syn::Ident Ok(&path.path.segments.last().as_ref().unwrap().ident) } -/// Generates code for a Function using an explicitly-named target. This will: -/// - Generate a module to host the generated types. -/// - Generate types based on the GraphQL schema for the Function input and output. -/// - Define a wrapper function that's exported to Wasm. The wrapper handles -/// decoding the input from STDIN, and encoding the output to STDOUT. -/// -/// -/// The macro takes the following parameters: -/// - `query_path`: A path to a GraphQL query, whose result will be used -/// as the input for the function invocation. The query MUST be named "Input". -/// - `schema_path`: A path to Shopify's GraphQL schema definition. Use the CLI -/// to download a fresh copy. -/// - `target` (optional): The API-specific handle for the target if the function name does not match the target handle as `snake_case` -/// - `module_name` (optional): The name of the generated module. -/// - default: The target handle as `snake_case` -/// - `extern_enums` (optional): A list of Enums for which an external type should be used. -/// For those, code generation will be skipped. This is useful for large enums -/// which can increase binary size, or for enums shared between multiple targets. -/// Example: `extern_enums = ["LanguageCode"]` -/// - default: `["LanguageCode", "CountryCode", "CurrencyCode"]` +/// Generates code for a Function. This will define a wrapper function that is exported to Wasm. +/// The wrapper handles deserializing the input and serializing the output. #[proc_macro_attribute] -pub fn shopify_function_target( +pub fn shopify_function( attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let ast = parse_macro_input!(item as syn::ItemFn); - let args = parse_macro_input!(attr as ShopifyFunctionTargetArgs); + if !attr.is_empty() { + return quote! {compile_error!("Shopify functions don't accept attributes");}.into(); + } let function_name = &ast.sig.ident; let function_name_string = function_name.to_string(); - let target_handle_string = args.target.map_or(function_name_string.clone(), |target| { - target - .value() - .split('.') - .collect::>() - .last() - .unwrap() - .to_case(Case::Snake) - }); - let module_name = args.module_name.map_or( - Ident::new(&target_handle_string, Span::mixed_site()), - |module_name| Ident::new(module_name.value().as_str(), Span::mixed_site()), - ); - - let query_path = args - .query_path - .expect("No value given for query_path") - .value(); - let schema_path = args - .schema_path - .expect("No value given for schema_path") - .value(); - let extern_enums = args - .extern_enums - .as_ref() - .map(extract_extern_enums) - .unwrap_or_else(default_exter_enums); - - let input_struct = generate_input_struct( - query_path.as_str(), - schema_path.as_str(), - extern_enums.as_slice(), - ); + let export_function_name = format_ident!("{}_export", function_name); - if let Err(error) = extract_shopify_function_return_type(&ast) { - return error.to_compile_error().into(); + if ast.sig.inputs.len() != 1 { + return quote! {compile_error!("Shopify functions need exactly one input parameter");} + .into(); } - let output_result_type = extract_shopify_function_return_type(&ast) - .unwrap() - .to_token_stream() - .to_string(); - let output_query = format!( - "mutation Output($result: {}!) {{\n {}(result: $result)\n}}\n", - output_result_type, - &target_handle_string.to_case(Case::Camel) - ); - let output_struct = - generate_output_struct(&output_query, schema_path.as_str(), extern_enums.as_slice()); + + let input_type = match &ast.sig.inputs.first().unwrap() { + FnArg::Typed(input) => input.ty.as_ref(), + FnArg::Receiver(_) => { + return quote! {compile_error!("Shopify functions can't have a receiver");}.into() + } + }; if let Err(error) = extract_shopify_function_return_type(&ast) { return error.to_compile_error().into(); } - let input_stream = args - .input_stream - .map_or(quote! { std::io::stdin() }, |stream| { - stream.to_token_stream() - }); - let output_stream = args - .output_stream - .map_or(quote! { std::io::stdout() }, |stream| { - stream.to_token_stream() - }); - quote! { - pub mod #module_name { - use super::*; - use std::io::Write; - - #input_struct - #output_struct - - #[shopify_function( - input_stream = #input_stream, - output_stream = #output_stream - )] - pub #ast - - #[export_name = #function_name_string] - pub extern "C" fn export() { - main().unwrap(); - #output_stream.flush().unwrap(); - } + #[export_name = #function_name_string] + pub extern "C" fn #export_function_name() { + let mut context = shopify_function::wasm_api::Context::new(); + let root_value = context.input_get().expect("Failed to get input"); + let mut input: #input_type = shopify_function::wasm_api::Deserialize::deserialize(&root_value).expect("Failed to deserialize input"); + let result = #function_name(input).expect("Failed to call function"); + shopify_function::wasm_api::Serialize::serialize(&result, &mut context).expect("Failed to serialize output"); + context.finalize_output().expect("Failed to finalize output"); } - pub use #module_name::#function_name; + + #ast } .into() } -/// Generate the types to interact with Shopify's API. +const DEFAULT_EXTERN_ENUMS: &[&str] = &["LanguageCode", "CountryCode", "CurrencyCode"]; + +mod kw { + syn::custom_keyword!(input_stream); + syn::custom_keyword!(output_stream); +} + +/// Generates Rust types from GraphQL schema definitions and queries. +/// +/// ### Arguments +/// +/// **Positional:** +/// +/// 1. String literal with path to the file containing the schema definition. If relative, should be with respect to +/// the project root (wherever `Cargo.toml` is located). +/// +/// **Optional keyword:** +/// +/// _enums_as_str_: Optional list of enum names for which the generated code should use string types instead of +/// a fully formed enum. Defaults to `["LanguageCode", "CountryCode", "CurrencyCode"]`. +/// +/// ### Trait implementations +/// +/// By default, will implement `PartialEq`, and `Debug` for all input and enum types. Enums will also implement `Copy`. +/// For types corresponding to values returned from queries, the `shopify_function::wasm_api::Deserialize` trait +/// is implemented. For types that would +/// be arguments to a query, the `shopify_function::wasm_api::Serialize` trait is implemented. +/// +/// ### Usage +/// +/// Must be used with a module. Inside the module, type aliases must be defined for any custom scalars in the schema. +/// +/// #### Queries +/// +/// To use a query, define a module within the aforementioned module, and annotate it with +/// `#[query("path/to/query.graphql")]`, where the argument is a string literal path to the query document, or the +/// query contents enclosed in square brackets. +/// +/// ##### Custom scalar overrides +/// +/// To override the type of a custom scalar for a path within a query, use the `custom_scalar_overrides` named argument +/// inside of the `#[query(...)]` attribute. The argument is a map from a path to a type, where the path is a string literal +/// path to the field in the query, and the type is the type to override the field with. +/// +/// For example, with the following query: +/// ```graphql +/// query MyQuery { +/// myField: myScalar! +/// } +/// ``` +/// do something like the following: +/// ```ignore +/// #[query("path/to/query.graphql", custom_scalar_overrides = { +/// "MyQuery.myField" => ::std::primitive::i32, +/// })] +/// ``` +/// Any type path that does not start with `::` is assumed to be relative to the schema definition module. +/// +/// ### Naming /// -/// The macro generates two inline modules: `input` and `output`. The -/// modules generate Rust types from the GraphQL schema file for the Function input -/// and output respectively. +/// To generate idiomatic Rust code, some renaming of types, enum variants, and fields is performed. Types are +/// renamed with `PascalCase`, as are enum variants. Fields are renamed with `snake_case`. /// -/// The macro takes the following parameters: -/// - `query_path`: A path to a GraphQL query, whose result will be used -/// as the input for the function invocation. The query MUST be named "Input". -/// - `schema_path`: A path to Shopify's GraphQL schema definition. Use the CLI -/// to download a fresh copy. -/// - `extern_enums` (optional): A list of Enums for which an external type should be used. -/// For those, code generation will be skipped. This is useful for large enums -/// which can increase binary size, or for enums shared between multiple targets. -/// Example: `extern_enums = ["LanguageCode"]` -/// - default: `["LanguageCode", "CountryCode", "CurrencyCode"]` -#[proc_macro] -pub fn generate_types(attr: proc_macro::TokenStream) -> proc_macro::TokenStream { - let args = parse_macro_input!(attr as GenerateTypeArgs); - - let query_path = args - .query_path - .expect("No value given for query_path") - .value(); - let schema_path = args - .schema_path - .expect("No value given for schema_path") - .value(); - let extern_enums = args - .extern_enums - .as_ref() - .map(extract_extern_enums) - .unwrap_or_else(default_exter_enums); - - let input_struct = generate_input_struct( - query_path.as_str(), - schema_path.as_str(), - extern_enums.as_slice(), - ); - let output_query = - "mutation Output($result: FunctionResult!) {\n handleResult(result: $result)\n}\n"; - let output_struct = generate_output_struct(output_query, &schema_path, extern_enums.as_slice()); +/// ### Query restrictions +/// +/// In order to keep the type generation code relatively simple, there are some restrictions on the queries that are +/// permitted. This may be relaxed in future versions. +/// * Selection sets on object and interface types must contain either a single fragment spread, or entirely field +/// selections. +/// * Selection sets on union types must contain either a single fragment spread, or both an unaliased `__typename` +/// selection and inline fragments for all or a subset of the objects contained in the union. +#[proc_macro_attribute] +pub fn typegen( + attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let mut input = syn::parse_macro_input!(attr as BluejayInput); + let mut module = syn::parse_macro_input!(item as syn::ItemMod); + + if let Some(borrow) = input.borrow.as_ref() { + if borrow.value() { + let error = syn::Error::new_spanned( + borrow, + "`borrow` attribute must be `false` or omitted for Shopify Functions", + ); + return error.to_compile_error().into(); + } + } - quote! { - #input_struct - #output_struct + if input.enums_as_str.is_empty() { + let enums_as_str = DEFAULT_EXTERN_ENUMS + .iter() + .map(|enum_name| syn::LitStr::new(enum_name, Span::mixed_site())) + .collect::>(); + input.enums_as_str = syn::parse_quote! { #(#enums_as_str),* }; } - .into() -} -const DEFAULT_EXTERN_ENUMS: &[&str] = &["LanguageCode", "CountryCode", "CurrencyCode"]; + let string_known_custom_scalar_type = KnownCustomScalarType { + type_for_borrowed: None, // we disallow borrowing + type_for_owned: syn::parse_quote! { ::std::string::String }, + }; -fn generate_input_struct( - query_path: &str, - schema_path: &str, - extern_enums: &[String], -) -> TokenStream { - quote! { - #[derive(graphql_client::GraphQLQuery, Clone, Debug, serde::Deserialize, PartialEq)] - #[graphql( - query_path = #query_path, - schema_path = #schema_path, - response_derives = "Clone,Debug,PartialEq,Deserialize,Serialize", - variables_derives = "Clone,Debug,PartialEq,Deserialize", - extern_enums(#(#extern_enums),*), - skip_serializing_none - )] - pub struct Input; + let known_custom_scalar_types = HashMap::from([ + (String::from("Id"), string_known_custom_scalar_type.clone()), + (String::from("Url"), string_known_custom_scalar_type.clone()), + ( + String::from("Handle"), + string_known_custom_scalar_type.clone(), + ), + ( + String::from("Date"), + string_known_custom_scalar_type.clone(), + ), + ( + String::from("DateTime"), + string_known_custom_scalar_type.clone(), + ), + ( + String::from("DateTimeWithoutTimezone"), + string_known_custom_scalar_type.clone(), + ), + ( + String::from("TimeWithoutTimezone"), + string_known_custom_scalar_type.clone(), + ), + ( + String::from("Void"), + KnownCustomScalarType { + type_for_borrowed: None, + type_for_owned: syn::parse_quote! { () }, + }, + ), + ( + String::from("Json"), + KnownCustomScalarType { + type_for_borrowed: None, + type_for_owned: syn::parse_quote! { ::shopify_function::scalars::JsonValue }, + }, + ), + ( + String::from("Decimal"), + KnownCustomScalarType { + type_for_borrowed: None, + type_for_owned: syn::parse_quote! { ::shopify_function::scalars::Decimal }, + }, + ), + ]); + + if let Err(error) = generate_schema( + input, + &mut module, + known_custom_scalar_types, + ShopifyFunctionCodeGenerator, + ) { + return error.to_compile_error().into(); } + + module.to_token_stream().into() } -fn graphql_codegen_options( - operation_name: String, - extern_enums: &[String], -) -> GraphQLClientCodegenOptions { - let mut options = GraphQLClientCodegenOptions::new(CodegenMode::Derive); - options.set_operation_name(operation_name); - options.set_response_derives("Clone,Debug,PartialEq,Deserialize,Serialize".to_string()); - options.set_variables_derives("Clone,Debug,PartialEq,Deserialize".to_string()); - options.set_skip_serializing_none(true); - options.set_module_visibility( - syn::VisPublic { - pub_token: ::default(), - } - .into(), - ); - options.set_extern_enums(extern_enums.to_vec()); +struct ShopifyFunctionCodeGenerator; + +impl CodeGenerator for ShopifyFunctionCodeGenerator { + fn fields_for_executable_struct( + &self, + executable_struct: &bluejay_typegen_codegen::ExecutableStruct, + ) -> syn::Fields { + let once_cell_fields: Vec = executable_struct + .fields() + .iter() + .map(|field| { + let field_name_ident = names::field_ident(field.graphql_name()); + let field_type = Self::type_for_field(executable_struct, field.r#type(), false); + + parse_quote! { + #field_name_ident: ::std::cell::OnceCell<#field_type> + } + }) + .collect(); + + let fields_named: syn::FieldsNamed = parse_quote! { + { + __wasm_value: shopify_function::wasm_api::Value, + #(#once_cell_fields),* + } + }; + fields_named.into() + } - options -} + fn additional_impls_for_executable_struct( + &self, + executable_struct: &bluejay_typegen_codegen::ExecutableStruct, + ) -> Vec { + let name_ident = names::type_ident(executable_struct.parent_name()); + + let once_cell_field_values: Vec = executable_struct + .fields() + .iter() + .map(|field| { + let field_name_ident = names::field_ident(field.graphql_name()); + + parse_quote! { + #field_name_ident: ::std::cell::OnceCell::new() + } + }) + .collect(); + + let deserialize_impl = parse_quote! { + impl shopify_function::wasm_api::Deserialize for #name_ident { + fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { + Ok(Self { + __wasm_value: *value, + #(#once_cell_field_values),* + }) + } + } + }; + + let accessors: Vec = executable_struct + .fields() + .iter() + .map(|field| { + let field_name_ident = names::field_ident(field.graphql_name()); + let field_name_lit_str = syn::LitStr::new(field.graphql_name(), Span::mixed_site()); + let field_type = Self::type_for_field(executable_struct, field.r#type(), true); + + let properly_referenced_value = + Self::reference_variable_for_type(field.r#type(), &format_ident!("value")); + + let description: Option = field.description().map(|description| { + let description_lit_str = syn::LitStr::new(description, Span::mixed_site()); + parse_quote! { #[doc = #description_lit_str] } + }); + + parse_quote! { + #description + pub fn #field_name_ident(&self) -> #field_type { + static INTERNED_FIELD_NAME: shopify_function::wasm_api::CachedInternedStringId = shopify_function::wasm_api::CachedInternedStringId::new(#field_name_lit_str, ); + let interned_string_id = INTERNED_FIELD_NAME.load_from_value(&self.__wasm_value); + + let value = self.#field_name_ident.get_or_init(|| { + let value = self.__wasm_value.get_interned_obj_prop(interned_string_id); + shopify_function::wasm_api::Deserialize::deserialize(&value).unwrap() + }); + #properly_referenced_value + } + } + }) + .collect(); + + let accessor_impl = parse_quote! { + impl #name_ident { + #(#accessors)* + } + }; -fn generate_output_struct( - query: &str, - schema_path: &str, - extern_enums: &[String], -) -> proc_macro2::TokenStream { - let options = graphql_codegen_options("Output".to_string(), extern_enums); - let cargo_manifest_dir = - std::env::var("CARGO_MANIFEST_DIR").expect("Error reading CARGO_MANIFEST_DIR from env"); - let schema_path = Path::new(&cargo_manifest_dir).join(schema_path); - let token_stream = generate_module_token_stream_from_string(query, &schema_path, options) - .expect("Error generating Output struct"); + vec![deserialize_impl, accessor_impl] + } - quote! { - #token_stream - pub struct Output; + fn additional_impls_for_executable_enum( + &self, + executable_enum: &bluejay_typegen_codegen::ExecutableEnum, + ) -> Vec { + let name_ident = names::type_ident(executable_enum.parent_name()); + + let match_arms: Vec = executable_enum + .variants() + .iter() + .map(|variant| { + let variant_name_ident = names::enum_variant_ident(variant.parent_name()); + let variant_name_lit_str = syn::LitStr::new(variant.parent_name(), Span::mixed_site()); + + parse_quote! { + #variant_name_lit_str => shopify_function::wasm_api::Deserialize::deserialize(value).map(Self::#variant_name_ident), + } + }).collect(); + + vec![parse_quote! { + impl shopify_function::wasm_api::Deserialize for #name_ident { + fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { + let typename = value.get_obj_prop("__typename"); + let typename_str: String = shopify_function::wasm_api::Deserialize::deserialize(&typename)?; + + match typename_str.as_str() { + #(#match_arms)* + _ => Ok(Self::Other), + } + } + } + }] + } + + fn additional_impls_for_enum( + &self, + enum_type_definition: &impl EnumTypeDefinition, + ) -> Vec { + let name_ident = names::type_ident(enum_type_definition.name()); + + let from_str_match_arms: Vec = enum_type_definition + .enum_value_definitions() + .iter() + .map(|evd| { + let variant_name_ident = names::enum_variant_ident(evd.name()); + let variant_name_lit_str = syn::LitStr::new(evd.name(), Span::mixed_site()); + + parse_quote! { + #variant_name_lit_str => Self::#variant_name_ident, + } + }) + .collect(); + + let as_str_match_arms: Vec = enum_type_definition + .enum_value_definitions() + .iter() + .map(|evd| { + let variant_name_ident = names::enum_variant_ident(evd.name()); + let variant_name_lit_str = syn::LitStr::new(evd.name(), Span::mixed_site()); + + parse_quote! { + Self::#variant_name_ident => #variant_name_lit_str, + } + }) + .collect(); + + let non_trait_method_impls = parse_quote! { + impl #name_ident { + pub fn from_str(s: &str) -> Self { + match s { + #(#from_str_match_arms)* + _ => Self::Other, + } + } + + fn as_str(&self) -> &str { + match self { + #(#as_str_match_arms)* + Self::Other => panic!("Cannot serialize `Other` variant"), + } + } + } + }; + + let serialize_impl = parse_quote! { + impl shopify_function::wasm_api::Serialize for #name_ident { + fn serialize(&self, context: &mut shopify_function::wasm_api::Context) -> ::std::result::Result<(), shopify_function::wasm_api::write::Error> { + let str_value = self.as_str(); + context.write_utf8_str(str_value) + } + } + }; + + let deserialize_impl = parse_quote! { + impl shopify_function::wasm_api::Deserialize for #name_ident { + fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { + let str_value: String = shopify_function::wasm_api::Deserialize::deserialize(value)?; + + Ok(Self::from_str(&str_value)) + } + } + }; + + let display_impl = parse_quote! { + impl std::fmt::Display for #name_ident { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_str()) + } + } + }; + + vec![ + non_trait_method_impls, + serialize_impl, + deserialize_impl, + display_impl, + ] } -} -fn extract_extern_enums(extern_enums: &ExprArray) -> Vec { - let extern_enum_error_msg = r#"The `extern_enums` attribute expects comma separated string literals\n\n= help: use `extern_enums = ["Enum1", "Enum2"]`"#; - extern_enums - .elems - .iter() - .map(|expr| { - let value = match expr { - Expr::Lit(lit) => lit.lit.clone(), - _ => panic!("{}", extern_enum_error_msg), - }; - match value { - syn::Lit::Str(lit) => lit.value(), - _ => panic!("{}", extern_enum_error_msg), + fn additional_impls_for_input_object( + &self, + #[allow(unused_variables)] input_object_type_definition: &impl InputObjectTypeDefinition, + ) -> Vec { + let name_ident = names::type_ident(input_object_type_definition.name()); + + let field_statements: Vec = input_object_type_definition + .input_field_definitions() + .iter() + .flat_map(|ivd| { + let field_name_ident = names::field_ident(ivd.name()); + let field_name_lit_str = syn::LitStr::new(ivd.name(), Span::mixed_site()); + + vec![ + parse_quote! { + context.write_utf8_str(#field_name_lit_str)?; + }, + parse_quote! { + self.#field_name_ident.serialize(context)?; + }, + ] + }) + .collect(); + + let num_fields = input_object_type_definition.input_field_definitions().len(); + + let serialize_impl = parse_quote! { + impl shopify_function::wasm_api::Serialize for #name_ident { + fn serialize(&self, context: &mut shopify_function::wasm_api::Context) -> ::std::result::Result<(), shopify_function::wasm_api::write::Error> { + context.write_object( + |context| { + #(#field_statements)* + Ok(()) + }, + #num_fields, + ) + } } - }) - .collect() + }; + + vec![serialize_impl] + } + + fn additional_impls_for_one_of_input_object( + &self, + input_object_type_definition: &impl InputObjectTypeDefinition, + ) -> Vec { + let name_ident = names::type_ident(input_object_type_definition.name()); + + let match_arms: Vec = input_object_type_definition + .input_field_definitions() + .iter() + .map(|ivd| { + let variant_ident = names::enum_variant_ident(ivd.name()); + let field_name_lit_str = syn::LitStr::new(ivd.name(), Span::mixed_site()); + + parse_quote! { + Self::#variant_ident(value) => { + context.write_utf8_str(#field_name_lit_str)?; + shopify_function::wasm_api::Serialize::serialize(value, context)?; + } + } + }) + .collect(); + + let serialize_impl = parse_quote! { + impl shopify_function::wasm_api::Serialize for #name_ident { + fn serialize(&self, context: &mut shopify_function::wasm_api::Context) -> ::std::result::Result<(), shopify_function::wasm_api::write::Error> { + context.write_object(|context| { + match self { + #(#match_arms)* + } + Ok(()) + }, 1) + } + } + }; + + vec![serialize_impl] + } + + fn attributes_for_enum( + &self, + _enum_type_definition: &impl EnumTypeDefinition, + ) -> Vec { + vec![parse_quote! { #[derive(Debug, PartialEq, Clone, Copy)] }] + } + + fn attributes_for_input_object( + &self, + _input_object_type_definition: &impl InputObjectTypeDefinition, + ) -> Vec { + vec![parse_quote! { #[derive(Debug, PartialEq, Clone)] }] + } + + fn attributes_for_one_of_input_object( + &self, + _input_object_type_definition: &impl InputObjectTypeDefinition, + ) -> Vec { + vec![parse_quote! { #[derive(Debug, PartialEq, Clone)] }] + } } -fn default_exter_enums() -> Vec { - DEFAULT_EXTERN_ENUMS.iter().map(|e| e.to_string()).collect() +impl ShopifyFunctionCodeGenerator { + fn type_for_field( + executable_struct: &ExecutableStruct, + r#type: &WrappedExecutableType, + reference: bool, + ) -> syn::Type { + match r#type { + WrappedExecutableType::Base(base) => { + let base_type = executable_struct.compute_base_type(base); + if reference { + parse_quote! { &#base_type } + } else { + base_type + } + } + WrappedExecutableType::Optional(inner) => { + let inner_type = Self::type_for_field(executable_struct, inner, reference); + parse_quote! { ::std::option::Option<#inner_type> } + } + WrappedExecutableType::Vec(inner) => { + let inner_type = Self::type_for_field(executable_struct, inner, false); + if reference { + parse_quote! { &[#inner_type] } + } else { + parse_quote! { ::std::vec::Vec<#inner_type> } + } + } + } + } + + fn reference_variable_for_type( + r#type: &WrappedExecutableType, + variable: &syn::Ident, + ) -> syn::Expr { + match r#type { + WrappedExecutableType::Base(_) | WrappedExecutableType::Vec(_) => { + parse_quote! { &#variable } + } + WrappedExecutableType::Optional(inner) => { + let inner_reference = Self::reference_variable_for_type(inner, variable); + parse_quote! { ::std::option::Option::as_ref(#inner_reference) } + } + } + } } -#[cfg(test)] -mod tests {} +#[proc_macro_derive(Deserialize, attributes(shopify_function))] +pub fn derive_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = syn::parse_macro_input!(input as syn::DeriveInput); -mod kw { - syn::custom_keyword!(target); - syn::custom_keyword!(module_name); - syn::custom_keyword!(query_path); - syn::custom_keyword!(schema_path); - syn::custom_keyword!(input_stream); - syn::custom_keyword!(output_stream); - syn::custom_keyword!(extern_enums); + derive_deserialize_for_derive_input(&input) + .map(|impl_item| impl_item.to_token_stream().into()) + .unwrap_or_else(|error| error.to_compile_error().into()) +} + +fn derive_deserialize_for_derive_input(input: &syn::DeriveInput) -> syn::Result { + match &input.data { + syn::Data::Struct(data) => match &data.fields { + syn::Fields::Named(fields) => { + let name_ident = &input.ident; + + let mut rename_all: Option = None; + + for attr in input.attrs.iter() { + if attr.path().is_ident("shopify_function") { + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("rename_all") { + rename_all = Some(meta.value()?.parse()?); + Ok(()) + } else { + Err(meta.error("unrecognized repr")) + } + })?; + } + } + + let case_style = match rename_all { + Some(rename_all) => match rename_all.value().as_str() { + "camelCase" => Some(Case::Camel), + "snake_case" => Some(Case::Snake), + "kebab-case" => Some(Case::Kebab), + _ => { + return Err(syn::Error::new_spanned( + rename_all, + "unrecognized rename_all", + )) + } + }, + None => None, + }; + + let field_values: Vec = fields + .named + .iter() + .map(|field| { + let field_name_ident = field.ident.as_ref().expect("Named fields must have identifiers"); + let field_name_str = case_style.map_or_else(|| field_name_ident.to_string(), |case_style| { + field_name_ident.to_string().to_case(case_style) + }); + let field_name_lit_str = syn::LitStr::new(field_name_str.as_str(), Span::mixed_site()); + parse_quote! { + #field_name_ident: shopify_function::wasm_api::Deserialize::deserialize(&value.get_obj_prop(#field_name_lit_str))? + } + }) + .collect(); + + let deserialize_impl = parse_quote! { + impl shopify_function::wasm_api::Deserialize for #name_ident { + fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { + Ok(Self { + #(#field_values),* + }) + } + } + }; + + Ok(deserialize_impl) + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => Err(syn::Error::new_spanned( + input, + "Structs must have named fields to derive `Deserialize`", + )), + }, + syn::Data::Enum(_) => Err(syn::Error::new_spanned( + input, + "Enum types are not supported for deriving `Deserialize`", + )), + syn::Data::Union(_) => Err(syn::Error::new_spanned( + input, + "Union types are not supported for deriving `Deserialize`", + )), + } } From e5edf1284f9119e78bec7a5d853d3eb7af14bb86 Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Fri, 16 May 2025 16:53:52 -0400 Subject: [PATCH 14/40] Add `Deserialize` implementations for input objects --- example_with_targets/schema.graphql | 19 ++++++ example_with_targets/src/main.rs | 6 ++ example_with_targets/src/tests.rs | 6 ++ integration_tests/tests/integration_test.rs | 14 ++++- shopify_function_macro/src/lib.rs | 64 ++++++++++++++++++++- 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/example_with_targets/schema.graphql b/example_with_targets/schema.graphql index 32b9046..9505d2d 100644 --- a/example_with_targets/schema.graphql +++ b/example_with_targets/schema.graphql @@ -8,6 +8,11 @@ Only allow the field to be queried when targeting one of the specified targets. """ directive @restrictTarget(only: [String!]!) on FIELD_DEFINITION +""" +Requires that exactly one field must be supplied and that field must not be `null`. +""" +directive @oneOf on INPUT_OBJECT + """ Represents an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)-encoded date string. For example, September 7, 2019 is represented as `"2019-07-16"`. @@ -108,6 +113,20 @@ The result of API target B. """ input FunctionTargetBResult { name: String + operations: [Operation!]! +} + +input Operation @oneOf { + doThis: This + doThat: That +} + +input This { + thisField: String! +} + +input That { + thatField: Int! } """ diff --git a/example_with_targets/src/main.rs b/example_with_targets/src/main.rs index e1a6bb7..fa475d5 100644 --- a/example_with_targets/src/main.rs +++ b/example_with_targets/src/main.rs @@ -23,6 +23,12 @@ fn target_a(_input: schema::target_a::Input) -> Result Result { Ok(schema::FunctionTargetBResult { name: Some(format!("new name: \"{}\"", input.id())), + operations: vec![ + schema::Operation::DoThis(schema::This { + this_field: "this field".to_string(), + }), + schema::Operation::DoThat(schema::That { that_field: 42 }), + ], }) } diff --git a/example_with_targets/src/tests.rs b/example_with_targets/src/tests.rs index 2dc866e..4de5b0a 100644 --- a/example_with_targets/src/tests.rs +++ b/example_with_targets/src/tests.rs @@ -31,6 +31,12 @@ fn test_target_b() -> Result<()> { )?; let expected = crate::schema::FunctionTargetBResult { name: Some("new name: \"gid://shopify/Order/1234567890\"".to_string()), + operations: vec![ + crate::schema::Operation::DoThis(crate::schema::This { + this_field: "this field".to_string(), + }), + crate::schema::Operation::DoThat(crate::schema::That { that_field: 42 }), + ], }; assert_eq!(result, expected); diff --git a/integration_tests/tests/integration_test.rs b/integration_tests/tests/integration_test.rs index cc322e3..9d812b9 100644 --- a/integration_tests/tests/integration_test.rs +++ b/integration_tests/tests/integration_test.rs @@ -39,7 +39,19 @@ fn test_example_with_targets_target_b() -> Result<()> { assert_eq!( output, serde_json::json!({ - "name": "new name: \"gid://shopify/Order/1234567890\"" + "name": "new name: \"gid://shopify/Order/1234567890\"", + "operations": [ + { + "doThis": { + "thisField": "this field" + } + }, + { + "doThat": { + "thatField": 42 + } + } + ] }) ); Ok(()) diff --git a/shopify_function_macro/src/lib.rs b/shopify_function_macro/src/lib.rs index c8adf30..d8257f1 100644 --- a/shopify_function_macro/src/lib.rs +++ b/shopify_function_macro/src/lib.rs @@ -529,7 +529,27 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { } }; - vec![serialize_impl] + let field_values: Vec = input_object_type_definition + .input_field_definitions() + .iter() + .map(|ivd| { + let field_name_ident = names::field_ident(ivd.name()); + let field_name_lit_str = syn::LitStr::new(ivd.name(), Span::mixed_site()); + parse_quote! { #field_name_ident: shopify_function::wasm_api::Deserialize::deserialize(&value.get_obj_prop(#field_name_lit_str))? } + }) + .collect(); + + let deserialize_impl = parse_quote! { + impl shopify_function::wasm_api::Deserialize for #name_ident { + fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { + Ok(Self { + #(#field_values),* + }) + } + } + }; + + vec![serialize_impl, deserialize_impl] } fn additional_impls_for_one_of_input_object( @@ -567,7 +587,47 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { } }; - vec![serialize_impl] + let deserialize_match_arms: Vec = input_object_type_definition + .input_field_definitions() + .iter() + .map(|ivd| { + let field_name_lit_str = syn::LitStr::new(ivd.name(), Span::mixed_site()); + let variant_ident = names::enum_variant_ident(ivd.name()); + + parse_quote! { + #field_name_lit_str => { + let value = shopify_function::wasm_api::Deserialize::deserialize(&field_value)?; + Ok(Self::#variant_ident(value)) + } + } + }) + .collect(); + + let deserialize_impl = parse_quote! { + impl shopify_function::wasm_api::Deserialize for #name_ident { + fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { + let Some(obj_len) = value.obj_len() else { + return Err(shopify_function::wasm_api::read::Error::InvalidType); + }; + + if obj_len != 1 { + return Err(shopify_function::wasm_api::read::Error::InvalidType); + } + + let Some(field_name) = value.get_obj_key_at_index(0) else { + return Err(shopify_function::wasm_api::read::Error::InvalidType); + }; + let field_value = value.get_at_index(0); + + match field_name.as_str() { + #(#deserialize_match_arms)* + _ => Err(shopify_function::wasm_api::read::Error::InvalidType), + } + } + } + }; + + vec![serialize_impl, deserialize_impl] } fn attributes_for_enum( From 98228b59a8e808c13858e896afb41ee7e6615279 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 18:40:45 +0000 Subject: [PATCH 15/40] Bump syn from 2.0.100 to 2.0.101 Bumps [syn](https://github.com/dtolnay/syn) from 2.0.100 to 2.0.101. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.100...2.0.101) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.101 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2c1d20..b14773a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1331,9 +1331,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", From 83b9e92dfb6e0eb541ee9b671030428dc0ab4ab6 Mon Sep 17 00:00:00 2001 From: Andrew Hassan Date: Tue, 20 May 2025 10:37:57 -0400 Subject: [PATCH 16/40] Update crate version in docs to 1.0.0 --- shopify_function/README.md | 122 +++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/shopify_function/README.md b/shopify_function/README.md index 26a0180..6741ca4 100644 --- a/shopify_function/README.md +++ b/shopify_function/README.md @@ -10,66 +10,68 @@ A crate to help developers build [Shopify Functions]. See the [example_with_targets] for details on usage, or use the following guide to convert an existing Rust-based function. -## Updating an existing function using a version of `shopify_function` below `0.9.0` to use version `0.9.0` and above - - 1. In `main.rs`, add imports for `shopify_function`. - - ```rust - use shopify_function::prelude::*; - use shopify_function::Result; - ``` - - 1. In `main.rs`, add type generation, right under your imports. Remove any references to the `generate_types!` macro. Replace `./input.graphql` with the location of your input query file (e.g. `src/run.graphql`). - - ```rust - #[typegen("./schema.graphql")] - pub mod schema { - #[query("./input.graphql")] - pub mod input {} - } - ``` - - If your Function has multiple targets each with their own input query, add a nested module for each. For example: - ```rust - #[typegen("./schema.graphql")] - pub mod schema { - #[query("src/target_a.graphql")] - pub mod target_a {} - - #[query("src/target_b.graphql")] - pub mod target_b {} - } - ``` - - 1. In `main.rs`, ensure that you have a `main` function that returns an error indicating to invoke a named export: - - ```rust - fn main() { - eprintln!("Invoke a named import"); - std::process::exit(1); - } - ``` - - 1. Throughout all of your source files, replace any references to `#[shopify_function_target]` with the `shopify_function` macro, and change its return type. Typically, this is located in a file with a name equal to the target, e.g. `run.rs`. - - ```rust - #[shopify_function] - fn run(input: schema::input::Input) -> Result { - ``` - - 1. Update the types and fields utilized in the function to the new, auto-generated structs. For example: - | Old | New | - | --- | --- | - | `input::ResponseData` | `schema::input::Input` | - | `input::InputDiscountNodeMetafield` | `schema::input::input::discount_node::Metafield` | - | `input::InputDiscountNode` | `schema::input::input::DiscountNode` | - | `output::FunctionRunResult` | `schema::FunctionRunResult` | - | `output::DiscountApplicationStrategy::FIRST` | `schema::DiscountApplicationStrategy::First` | - - If referencing generated types from a file other than `main.rs` where they are defined, you'll need to import the schema. For example in `run.rs` you would need to add: - ```rust - use crate::schema; - ``` +## Updating an existing function using a version of `shopify_function` below `1.0.0` to use version `1.0.0` and above + +1. In `main.rs`, add imports for `shopify_function`. + + ```rust + use shopify_function::prelude::*; + use shopify_function::Result; + ``` + +1. In `main.rs`, add type generation, right under your imports. Remove any references to the `generate_types!` macro. Replace `./input.graphql` with the location of your input query file (e.g. `src/run.graphql`). + + ```rust + #[typegen("./schema.graphql")] + pub mod schema { + #[query("./input.graphql")] + pub mod input {} + } + ``` + + If your Function has multiple targets each with their own input query, add a nested module for each. For example: + + ```rust + #[typegen("./schema.graphql")] + pub mod schema { + #[query("src/target_a.graphql")] + pub mod target_a {} + + #[query("src/target_b.graphql")] + pub mod target_b {} + } + ``` + +1. In `main.rs`, ensure that you have a `main` function that returns an error indicating to invoke a named export: + + ```rust + fn main() { + eprintln!("Invoke a named import"); + std::process::exit(1); + } + ``` + +1. Throughout all of your source files, replace any references to `#[shopify_function_target]` with the `shopify_function` macro, and change its return type. Typically, this is located in a file with a name equal to the target, e.g. `run.rs`. + + ```rust + #[shopify_function] + fn run(input: schema::input::Input) -> Result { + ``` + +1. Update the types and fields utilized in the function to the new, auto-generated structs. For example: + | Old | New | + | --- | --- | + | `input::ResponseData` | `schema::input::Input` | + | `input::InputDiscountNodeMetafield` | `schema::input::input::discount_node::Metafield` | + | `input::InputDiscountNode` | `schema::input::input::DiscountNode` | + | `output::FunctionRunResult` | `schema::FunctionRunResult` | + | `output::DiscountApplicationStrategy::FIRST` | `schema::DiscountApplicationStrategy::First` | + + If referencing generated types from a file other than `main.rs` where they are defined, you'll need to import the schema. For example in `run.rs` you would need to add: + + ```rust + use crate::schema; + ``` ## Viewing the generated types From 4c0c28a313b60b71540079ced9d595b1e5f41832 Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Tue, 20 May 2025 12:01:11 -0400 Subject: [PATCH 17/40] Improve some macro hygiene --- shopify_function/tests/macro_hygiene_test.rs | 81 ++++++++++++++++++++ shopify_function_macro/src/lib.rs | 44 ++++++----- 2 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 shopify_function/tests/macro_hygiene_test.rs diff --git a/shopify_function/tests/macro_hygiene_test.rs b/shopify_function/tests/macro_hygiene_test.rs new file mode 100644 index 0000000..fdf30e9 --- /dev/null +++ b/shopify_function/tests/macro_hygiene_test.rs @@ -0,0 +1,81 @@ +use shopify_function::prelude::*; +use shopify_function::wasm_api::Deserialize; + +#[typegen([ + type Ok { + value: String + } + + type Err { + value: String + } + + union Result = Ok | Err + + type Some { + value: String + } + + type None { + // this doesn't really make sense but types must have one field + value: String + } + + union Option = Some | None + + type Query { + result: Result! + option: Option! + } +], enums_as_str = ["__TypeKind"])] +mod schema { + #[query([ + query Query { + result { + __typename + ... on Ok { + value + } + ... on Err { + value + } + } + option { + __typename + ... on Some { + value + } + ... on None { + value + } + } + } + ])] + pub mod query {} +} + +#[test] +fn test_macro_hygiene() { + let value = serde_json::json!({ + "result": { + "__typename": "Ok", + "value": "test", + }, + "option": { + "__typename": "Some", + "value": "test", + }, + }); + let context = shopify_function::wasm_api::Context::new_with_input(value); + let value = context.input_get().unwrap(); + + let result = schema::query::Query::deserialize(&value).unwrap(); + assert!(matches!( + result.result(), + schema::query::query::Result::Ok(_) + )); + assert!(matches!( + result.option(), + schema::query::query::Option::Some(_) + )); +} diff --git a/shopify_function_macro/src/lib.rs b/shopify_function_macro/src/lib.rs index d8257f1..c224f8b 100644 --- a/shopify_function_macro/src/lib.rs +++ b/shopify_function_macro/src/lib.rs @@ -393,11 +393,11 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { impl shopify_function::wasm_api::Deserialize for #name_ident { fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { let typename = value.get_obj_prop("__typename"); - let typename_str: String = shopify_function::wasm_api::Deserialize::deserialize(&typename)?; + let typename_str: ::std::string::String = shopify_function::wasm_api::Deserialize::deserialize(&typename)?; match typename_str.as_str() { #(#match_arms)* - _ => Ok(Self::Other), + _ => ::std::result::Result::Ok(Self::Other), } } } @@ -445,7 +445,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { } } - fn as_str(&self) -> &str { + fn as_str(&self) -> &::std::primitive::str { match self { #(#as_str_match_arms)* Self::Other => panic!("Cannot serialize `Other` variant"), @@ -466,9 +466,9 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { let deserialize_impl = parse_quote! { impl shopify_function::wasm_api::Deserialize for #name_ident { fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { - let str_value: String = shopify_function::wasm_api::Deserialize::deserialize(value)?; + let str_value: ::std::string::String = shopify_function::wasm_api::Deserialize::deserialize(value)?; - Ok(Self::from_str(&str_value)) + ::std::result::Result::Ok(Self::from_str(&str_value)) } } }; @@ -521,7 +521,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { context.write_object( |context| { #(#field_statements)* - Ok(()) + ::std::result::Result::Ok(()) }, #num_fields, ) @@ -542,7 +542,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { let deserialize_impl = parse_quote! { impl shopify_function::wasm_api::Deserialize for #name_ident { fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { - Ok(Self { + ::std::result::Result::Ok(Self { #(#field_values),* }) } @@ -581,7 +581,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { match self { #(#match_arms)* } - Ok(()) + ::std::result::Result::Ok(()) }, 1) } } @@ -597,7 +597,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { parse_quote! { #field_name_lit_str => { let value = shopify_function::wasm_api::Deserialize::deserialize(&field_value)?; - Ok(Self::#variant_ident(value)) + ::std::result::Result::Ok(Self::#variant_ident(value)) } } }) @@ -606,22 +606,22 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { let deserialize_impl = parse_quote! { impl shopify_function::wasm_api::Deserialize for #name_ident { fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { - let Some(obj_len) = value.obj_len() else { - return Err(shopify_function::wasm_api::read::Error::InvalidType); + let ::std::option::Option::Some(obj_len) = value.obj_len() else { + return ::std::result::Result::Err(shopify_function::wasm_api::read::Error::InvalidType); }; if obj_len != 1 { - return Err(shopify_function::wasm_api::read::Error::InvalidType); + return ::std::result::Result::Err(shopify_function::wasm_api::read::Error::InvalidType); } - let Some(field_name) = value.get_obj_key_at_index(0) else { - return Err(shopify_function::wasm_api::read::Error::InvalidType); + let ::std::option::Option::Some(field_name) = value.get_obj_key_at_index(0) else { + return ::std::result::Result::Err(shopify_function::wasm_api::read::Error::InvalidType); }; let field_value = value.get_at_index(0); match field_name.as_str() { #(#deserialize_match_arms)* - _ => Err(shopify_function::wasm_api::read::Error::InvalidType), + _ => ::std::result::Result::Err(shopify_function::wasm_api::read::Error::InvalidType), } } } @@ -634,21 +634,27 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { &self, _enum_type_definition: &impl EnumTypeDefinition, ) -> Vec { - vec![parse_quote! { #[derive(Debug, PartialEq, Clone, Copy)] }] + vec![ + parse_quote! { #[derive(::std::fmt::Debug, ::std::cmp::PartialEq, ::std::clone::Clone, ::std::marker::Copy)] }, + ] } fn attributes_for_input_object( &self, _input_object_type_definition: &impl InputObjectTypeDefinition, ) -> Vec { - vec![parse_quote! { #[derive(Debug, PartialEq, Clone)] }] + vec![ + parse_quote! { #[derive(::std::fmt::Debug, ::std::cmp::PartialEq, ::std::clone::Clone)] }, + ] } fn attributes_for_one_of_input_object( &self, _input_object_type_definition: &impl InputObjectTypeDefinition, ) -> Vec { - vec![parse_quote! { #[derive(Debug, PartialEq, Clone)] }] + vec![ + parse_quote! { #[derive(::std::fmt::Debug, ::std::cmp::PartialEq, ::std::clone::Clone)] }, + ] } } @@ -761,7 +767,7 @@ fn derive_deserialize_for_derive_input(input: &syn::DeriveInput) -> syn::Result< let deserialize_impl = parse_quote! { impl shopify_function::wasm_api::Deserialize for #name_ident { fn deserialize(value: &shopify_function::wasm_api::Value) -> ::std::result::Result { - Ok(Self { + ::std::result::Result::Ok(Self { #(#field_values),* }) } From 0a8fcf11fbfa5424bd62a55ea481a8ae49cbaacd Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Tue, 20 May 2025 14:36:58 -0400 Subject: [PATCH 18/40] Use released Wasm API crate --- Cargo.lock | 15 +++++++++------ shopify_function/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2c1d20..ca76f6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1242,8 +1242,9 @@ dependencies = [ [[package]] name = "shopify_function_provider" -version = "1.0.0" -source = "git+https://github.com/Shopify/shopify-function-wasm-api?rev=53b7f99c1cd67fc1f602495c745a9af166413573#53b7f99c1cd67fc1f602495c745a9af166413573" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eb4e60eb2f8c6e02b1f1e7634ef91738b1104b5bc2fa30458d10cd00917dbbf" dependencies = [ "bumpalo", "rmp", @@ -1252,8 +1253,9 @@ dependencies = [ [[package]] name = "shopify_function_wasm_api" -version = "0.0.1" -source = "git+https://github.com/Shopify/shopify-function-wasm-api?rev=53b7f99c1cd67fc1f602495c745a9af166413573#53b7f99c1cd67fc1f602495c745a9af166413573" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a57a2e64ef7d28cbe26bf591fd084093327d9d359e38355010720d818cd92ba9" dependencies = [ "rmp-serde", "serde_json", @@ -1264,8 +1266,9 @@ dependencies = [ [[package]] name = "shopify_function_wasm_api_core" -version = "0.0.1" -source = "git+https://github.com/Shopify/shopify-function-wasm-api?rev=53b7f99c1cd67fc1f602495c745a9af166413573#53b7f99c1cd67fc1f602495c745a9af166413573" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4842376f01b3abe6c78596085f29ea0d1b605873d2855f812738072c38e32c34" dependencies = [ "strum", ] diff --git a/shopify_function/Cargo.toml b/shopify_function/Cargo.toml index 6f588da..1abc6f9 100644 --- a/shopify_function/Cargo.toml +++ b/shopify_function/Cargo.toml @@ -9,7 +9,7 @@ description = "Crate to write Shopify Functions in Rust." [dependencies] serde_json = "1.0" shopify_function_macro = { version = "0.8.1", path = "../shopify_function_macro" } -shopify_function_wasm_api = { git = "https://github.com/Shopify/shopify-function-wasm-api", rev = "53b7f99c1cd67fc1f602495c745a9af166413573" } +shopify_function_wasm_api = "0.1.0" # Use the `small` feature of ryu (transitive dependency through serde_json) # to shave off ~9kb of the Wasm binary size. From ec70dc2cac4d87b9aa9f7dfccaea0993cc7df8be Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Tue, 20 May 2025 14:44:26 -0400 Subject: [PATCH 19/40] v1.0.0 --- Cargo.lock | 4 ++-- shopify_function/Cargo.toml | 4 ++-- shopify_function_macro/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca76f6b..9451a98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1220,7 +1220,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "shopify_function" -version = "0.8.1" +version = "1.0.0" dependencies = [ "ryu", "serde_json", @@ -1230,7 +1230,7 @@ dependencies = [ [[package]] name = "shopify_function_macro" -version = "0.8.1" +version = "1.0.0" dependencies = [ "bluejay-core", "bluejay-typegen-codegen", diff --git a/shopify_function/Cargo.toml b/shopify_function/Cargo.toml index 1abc6f9..9df9075 100644 --- a/shopify_function/Cargo.toml +++ b/shopify_function/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shopify_function" -version = "0.8.1" +version = "1.0.0" edition = "2021" authors = ["Surma ", "Delta Pham "] license = "MIT" @@ -8,7 +8,7 @@ description = "Crate to write Shopify Functions in Rust." [dependencies] serde_json = "1.0" -shopify_function_macro = { version = "0.8.1", path = "../shopify_function_macro" } +shopify_function_macro = { version = "1.0.0", path = "../shopify_function_macro" } shopify_function_wasm_api = "0.1.0" # Use the `small` feature of ryu (transitive dependency through serde_json) diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index 31053b6..4ccc6d2 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shopify_function_macro" -version = "0.8.1" +version = "1.0.0" edition = "2021" authors = ["Surma ", "Delta Pham "] license = "MIT" From 89289a302188f85d1cd26c0a64d725943c03f39d Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Wed, 21 May 2025 13:17:29 -0400 Subject: [PATCH 20/40] Optional array reference fix --- example_with_targets/b.graphql | 3 +++ example_with_targets/schema.graphql | 3 +++ shopify_function_macro/src/lib.rs | 15 ++++++++++----- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/example_with_targets/b.graphql b/example_with_targets/b.graphql index d408852..3fc98e3 100644 --- a/example_with_targets/b.graphql +++ b/example_with_targets/b.graphql @@ -1,4 +1,7 @@ query Input { id targetAResult + optionalArray + optionalArrayOfArrays + optionalArrayOfOptionalArrays } diff --git a/example_with_targets/schema.graphql b/example_with_targets/schema.graphql index 9505d2d..d2b6ce1 100644 --- a/example_with_targets/schema.graphql +++ b/example_with_targets/schema.graphql @@ -74,6 +74,9 @@ type Input { timeWithoutTimezone: TimeWithoutTimezone targetAResult: Int @restrictTarget(only: ["test.target-b"]) country: CountryCode + optionalArray: [String!] + optionalArrayOfArrays: [[String!]!] + optionalArrayOfOptionalArrays: [[String!]] } """ diff --git a/shopify_function_macro/src/lib.rs b/shopify_function_macro/src/lib.rs index c224f8b..f4584cc 100644 --- a/shopify_function_macro/src/lib.rs +++ b/shopify_function_macro/src/lib.rs @@ -339,7 +339,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { let field_type = Self::type_for_field(executable_struct, field.r#type(), true); let properly_referenced_value = - Self::reference_variable_for_type(field.r#type(), &format_ident!("value")); + Self::reference_variable_for_type(field.r#type(), &format_ident!("value_ref")); let description: Option = field.description().map(|description| { let description_lit_str = syn::LitStr::new(description, Span::mixed_site()); @@ -356,6 +356,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator { let value = self.__wasm_value.get_interned_obj_prop(interned_string_id); shopify_function::wasm_api::Deserialize::deserialize(&value).unwrap() }); + let value_ref = &value; #properly_referenced_value } } @@ -693,12 +694,16 @@ impl ShopifyFunctionCodeGenerator { variable: &syn::Ident, ) -> syn::Expr { match r#type { - WrappedExecutableType::Base(_) | WrappedExecutableType::Vec(_) => { - parse_quote! { &#variable } + WrappedExecutableType::Base(_) => { + parse_quote! { #variable } + } + WrappedExecutableType::Vec(_) => { + parse_quote! { #variable.as_slice()} } WrappedExecutableType::Optional(inner) => { - let inner_reference = Self::reference_variable_for_type(inner, variable); - parse_quote! { ::std::option::Option::as_ref(#inner_reference) } + let inner_variable = format_ident!("v_inner"); + let inner_reference = Self::reference_variable_for_type(inner, &inner_variable); + parse_quote! { ::std::option::Option::as_ref(#variable).map(|#inner_variable| #inner_reference) } } } } From 1cfb5113db52405551cf1a84b4aace367dee0579 Mon Sep 17 00:00:00 2001 From: David Cameron Date: Thu, 22 May 2025 14:01:41 -0400 Subject: [PATCH 21/40] Add support for default --- .../tests/derive_deserialize_default_test.rs | 161 ++++++++++++++++++ shopify_function_macro/src/lib.rs | 55 +++++- 2 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 shopify_function/tests/derive_deserialize_default_test.rs diff --git a/shopify_function/tests/derive_deserialize_default_test.rs b/shopify_function/tests/derive_deserialize_default_test.rs new file mode 100644 index 0000000..af42fa8 --- /dev/null +++ b/shopify_function/tests/derive_deserialize_default_test.rs @@ -0,0 +1,161 @@ +use shopify_function::prelude::*; +use shopify_function::wasm_api::Deserialize; + +#[derive(Deserialize, PartialEq, Debug, Default)] +#[shopify_function(rename_all = "camelCase")] +struct TestStructWithDefault { + // Field with default attribute - will use Default implementation when null + #[shopify_function(default)] + field_a: String, + + // Field with default attribute - will use Default implementation when null + #[shopify_function(default)] + field_b: i32, + + // Field without default attribute - will error when null + field_c: bool, +} + +// Define a struct with more complex default types +#[derive(Deserialize, PartialEq, Debug, Default)] +struct TestComplexDefaults { + // Standard primitive types + #[shopify_function(default)] + integer: i32, + + #[shopify_function(default)] + float: f64, + + #[shopify_function(default)] + string: String, + + #[shopify_function(default)] + boolean: bool, + + // Collection types + #[shopify_function(default)] + vector: Vec, + + #[shopify_function(default)] + option: Option, +} + +#[test] +fn test_derive_deserialize_with_default() { + // Test with all fields present + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "fieldA": "test", + "fieldB": 1, + "fieldC": true + })); + let root_value = context.input_get().unwrap(); + + let input = TestStructWithDefault::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestStructWithDefault { + field_a: "test".to_string(), + field_b: 1, + field_c: true + } + ); + + // Test with default fields set to null + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "fieldA": null, + "fieldB": null, + "fieldC": true + })); + let root_value = context.input_get().unwrap(); + + let input = TestStructWithDefault::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestStructWithDefault { + field_a: String::default(), // Empty string + field_b: i32::default(), // 0 + field_c: true + } + ); + + // Test with default fields missing + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "fieldC": true + })); + let root_value = context.input_get().unwrap(); + + // Our implementation is handling missing fields correctly by treating them as null values + let input = TestStructWithDefault::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestStructWithDefault { + field_a: String::default(), // Empty string + field_b: i32::default(), // 0 + field_c: true + } + ); +} + +#[test] +fn test_derive_deserialize_complex_defaults() { + // Test with all fields set to null + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "integer": null, + "float": null, + "string": null, + "boolean": null, + "vector": null, + "option": null + })); + let root_value = context.input_get().unwrap(); + + let input = TestComplexDefaults::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestComplexDefaults { + integer: 0, + float: 0.0, + string: String::new(), + boolean: false, + vector: Vec::new(), + option: None, + } + ); + + // Test with values provided + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "integer": 42, + "float": 3.19, + "string": "hello", + "boolean": true, + "vector": [1, 2, 3], + "option": "some value" + })); + let root_value = context.input_get().unwrap(); + + let input = TestComplexDefaults::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestComplexDefaults { + integer: 42, + float: 3.19, + string: "hello".to_string(), + boolean: true, + vector: vec![1, 2, 3], + option: Some("some value".to_string()), + } + ); +} + +#[test] +fn test_missing_non_default_field() { + // Missing a required field (field_c) + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "fieldA": "test", + "fieldB": 1 + })); + let root_value = context.input_get().unwrap(); + + // Should fail because field_c is required + TestStructWithDefault::deserialize(&root_value).unwrap_err(); +} diff --git a/shopify_function_macro/src/lib.rs b/shopify_function_macro/src/lib.rs index c224f8b..39ea841 100644 --- a/shopify_function_macro/src/lib.rs +++ b/shopify_function_macro/src/lib.rs @@ -704,6 +704,22 @@ impl ShopifyFunctionCodeGenerator { } } +/// Derives the `Deserialize` trait for structs to deserialize values from shopify_function_wasm_api::Value. +/// +/// The derive macro supports the following attributes: +/// +/// - `#[shopify_function(rename_all = "camelCase")]` - Converts field names from snake_case in Rust +/// to the specified case style ("camelCase", "snake_case", or "kebab-case") when deserializing. +/// +/// - `#[shopify_function(default)]` - When applied to a field, uses the `Default` implementation for +/// that field's type if either: +/// 1. The field's value is explicitly `null` in the JSON +/// 2. The field is missing entirely from the JSON object +/// +/// This is similar to serde's `#[serde(default)]` attribute, allowing structs to handle missing or null +/// fields gracefully by using their default values instead of returning an error. +/// +/// Note: Fields that use `#[shopify_function(default)]` must be a type that implements the `Default` trait. #[proc_macro_derive(Deserialize, attributes(shopify_function))] pub fn derive_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); @@ -758,8 +774,43 @@ fn derive_deserialize_for_derive_input(input: &syn::DeriveInput) -> syn::Result< field_name_ident.to_string().to_case(case_style) }); let field_name_lit_str = syn::LitStr::new(field_name_str.as_str(), Span::mixed_site()); - parse_quote! { - #field_name_ident: shopify_function::wasm_api::Deserialize::deserialize(&value.get_obj_prop(#field_name_lit_str))? + + // Check if field has #[shopify_function(default)] attribute + let has_default = field.attrs.iter().any(|attr| { + if attr.path().is_ident("shopify_function") { + let mut found = false; + let _ = attr.parse_nested_meta(|meta| { + if meta.path.is_ident("default") { + found = true; + } + Ok(()) + }); + found + } else { + false + } + }); + + if has_default { + // For fields with default attribute, check if value is null or missing + // This will use the Default implementation for the field type when either: + // 1. The field is explicitly null in the JSON (we get NanBox::null()) + // 2. The field is missing in the JSON (get_obj_prop returns a null value) + parse_quote! { + #field_name_ident: { + let prop = value.get_obj_prop(#field_name_lit_str); + if prop.is_null() { + ::std::default::Default::default() + } else { + shopify_function::wasm_api::Deserialize::deserialize(&prop)? + } + } + } + } else { + // For fields without default, use normal deserialization + parse_quote! { + #field_name_ident: shopify_function::wasm_api::Deserialize::deserialize(&value.get_obj_prop(#field_name_lit_str))? + } } }) .collect(); From 2d1130eaf05342c74d48024020c8cf4c8cc71f6c Mon Sep 17 00:00:00 2001 From: bkspace Date: Thu, 29 May 2025 08:42:31 +0100 Subject: [PATCH 22/40] Add field-level rename attribute support --- .../tests/derive_deserialize_test.rs | 100 ++++++++++++++++++ shopify_function_macro/src/lib.rs | 77 +++++++++----- 2 files changed, 152 insertions(+), 25 deletions(-) diff --git a/shopify_function/tests/derive_deserialize_test.rs b/shopify_function/tests/derive_deserialize_test.rs index 559fc5d..0ff7b23 100644 --- a/shopify_function/tests/derive_deserialize_test.rs +++ b/shopify_function/tests/derive_deserialize_test.rs @@ -33,3 +33,103 @@ fn test_derive_deserialize_error() { TestStruct::deserialize(&root_value).unwrap_err(); } + +#[derive(Deserialize, PartialEq, Debug)] +#[shopify_function(rename_all = "camelCase")] +struct TestStructWithRename { + #[shopify_function(rename = "customFieldName")] + field_one: String, + field_two: i32, + #[shopify_function(rename = "ANOTHER_CUSTOM_NAME")] + field_three: bool, +} + +#[test] +fn test_derive_deserialize_with_field_rename() { + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "customFieldName": "renamed field", + "fieldTwo": 42, + "ANOTHER_CUSTOM_NAME": true + })); + let root_value = context.input_get().unwrap(); + + let input = TestStructWithRename::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestStructWithRename { + field_one: "renamed field".to_string(), + field_two: 42, + field_three: true + } + ); +} + +#[test] +fn test_field_rename_takes_precedence_over_rename_all() { + // Test that field-level rename overrides struct-level rename_all + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "customFieldName": "correct", + "fieldOne": "incorrect", // This should be ignored + "fieldTwo": 10, + "ANOTHER_CUSTOM_NAME": false + })); + let root_value = context.input_get().unwrap(); + + let input = TestStructWithRename::deserialize(&root_value).unwrap(); + assert_eq!(input.field_one, "correct"); + assert_eq!(input.field_two, 10); + assert_eq!(input.field_three, false); +} + +#[derive(Deserialize, PartialEq, Debug)] +struct TestStructNoRenameAll { + #[shopify_function(rename = "different_name")] + original_name: String, + unchanged_field: i32, +} + +#[test] +fn test_field_rename_without_rename_all() { + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "different_name": "works", + "unchanged_field": 99 + })); + let root_value = context.input_get().unwrap(); + + let input = TestStructNoRenameAll::deserialize(&root_value).unwrap(); + assert_eq!( + input, + TestStructNoRenameAll { + original_name: "works".to_string(), + unchanged_field: 99 + } + ); +} + +#[derive(Deserialize, PartialEq, Debug, Default)] +struct TestValidAttributes { + #[shopify_function(rename = "custom")] + renamed_field: String, + + #[shopify_function(default)] + default_field: Option, + + // Multiple attributes on same field + #[shopify_function(rename = "both", default)] + renamed_and_default: String, +} + +#[test] +fn test_valid_attributes_combination() { + let context = shopify_function::wasm_api::Context::new_with_input(serde_json::json!({ + "custom": "renamed value", + // default_field is missing - should use default + "both": null // should use default for null + })); + let root_value = context.input_get().unwrap(); + + let input = TestValidAttributes::deserialize(&root_value).unwrap(); + assert_eq!(input.renamed_field, "renamed value"); + assert_eq!(input.default_field, None); + assert_eq!(input.renamed_and_default, String::default()); +} diff --git a/shopify_function_macro/src/lib.rs b/shopify_function_macro/src/lib.rs index 5290cbe..c382691 100644 --- a/shopify_function_macro/src/lib.rs +++ b/shopify_function_macro/src/lib.rs @@ -721,10 +721,14 @@ impl ShopifyFunctionCodeGenerator { /// 1. The field's value is explicitly `null` in the JSON /// 2. The field is missing entirely from the JSON object /// +/// - `#[shopify_function(rename = "custom_name")]` - When applied to a field, uses the specified +/// custom name for deserialization instead of the field's Rust name. This takes precedence over +/// any struct-level `rename_all` attribute. +/// /// This is similar to serde's `#[serde(default)]` attribute, allowing structs to handle missing or null /// fields gracefully by using their default values instead of returning an error. /// -/// Note: Fields that use `#[shopify_function(default)]` must be a type that implements the `Default` trait. +/// Note: Fields that use `#[shopify_function(default)]` must be a type that implements the `Default` trait. #[proc_macro_derive(Deserialize, attributes(shopify_function))] pub fn derive_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); @@ -734,6 +738,34 @@ pub fn derive_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenSt .unwrap_or_else(|error| error.to_compile_error().into()) } +#[derive(Default)] +struct FieldAttributes { + rename: Option, + has_default: bool, +} + +fn parse_field_attributes(field: &syn::Field) -> syn::Result { + let mut attributes = FieldAttributes::default(); + + for attr in field.attrs.iter() { + if attr.path().is_ident("shopify_function") { + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("rename") { + attributes.rename = Some(meta.value()?.parse::()?.value()); + Ok(()) + } else if meta.path.is_ident("default") { + attributes.has_default = true; + Ok(()) + } else { + Err(meta.error("unrecognized field attribute")) + } + })?; + } + } + + Ok(attributes) +} + fn derive_deserialize_for_derive_input(input: &syn::DeriveInput) -> syn::Result { match &input.data { syn::Data::Struct(data) => match &data.fields { @@ -775,33 +807,28 @@ fn derive_deserialize_for_derive_input(input: &syn::DeriveInput) -> syn::Result< .iter() .map(|field| { let field_name_ident = field.ident.as_ref().expect("Named fields must have identifiers"); - let field_name_str = case_style.map_or_else(|| field_name_ident.to_string(), |case_style| { - field_name_ident.to_string().to_case(case_style) - }); - let field_name_lit_str = syn::LitStr::new(field_name_str.as_str(), Span::mixed_site()); - // Check if field has #[shopify_function(default)] attribute - let has_default = field.attrs.iter().any(|attr| { - if attr.path().is_ident("shopify_function") { - let mut found = false; - let _ = attr.parse_nested_meta(|meta| { - if meta.path.is_ident("default") { - found = true; - } - Ok(()) - }); - found - } else { - false + let field_attrs = parse_field_attributes(field)?; + + let field_name_str = match field_attrs.rename { + Some(custom_name) => custom_name, + None => { + // Fall back to rename_all case transformation or original name + case_style.map_or_else( + || field_name_ident.to_string(), + |case_style| field_name_ident.to_string().to_case(case_style) + ) } - }); + }; - if has_default { + let field_name_lit_str = syn::LitStr::new(field_name_str.as_str(), Span::mixed_site()); + + if field_attrs.has_default { // For fields with default attribute, check if value is null or missing // This will use the Default implementation for the field type when either: // 1. The field is explicitly null in the JSON (we get NanBox::null()) // 2. The field is missing in the JSON (get_obj_prop returns a null value) - parse_quote! { + Ok(parse_quote! { #field_name_ident: { let prop = value.get_obj_prop(#field_name_lit_str); if prop.is_null() { @@ -810,15 +837,15 @@ fn derive_deserialize_for_derive_input(input: &syn::DeriveInput) -> syn::Result< shopify_function::wasm_api::Deserialize::deserialize(&prop)? } } - } + }) } else { // For fields without default, use normal deserialization - parse_quote! { + Ok(parse_quote! { #field_name_ident: shopify_function::wasm_api::Deserialize::deserialize(&value.get_obj_prop(#field_name_lit_str))? - } + }) } }) - .collect(); + .collect::>>()?; let deserialize_impl = parse_quote! { impl shopify_function::wasm_api::Deserialize for #name_ident { From b8d4eee786738de61720624688ce22f07516d665 Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Mon, 2 Jun 2025 10:09:12 -0400 Subject: [PATCH 23/40] v1.1.0 --- Cargo.lock | 4 ++-- shopify_function/Cargo.toml | 4 ++-- shopify_function_macro/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fce280..b7e867a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1220,7 +1220,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "shopify_function" -version = "1.0.0" +version = "1.1.0" dependencies = [ "ryu", "serde_json", @@ -1230,7 +1230,7 @@ dependencies = [ [[package]] name = "shopify_function_macro" -version = "1.0.0" +version = "1.1.0" dependencies = [ "bluejay-core", "bluejay-typegen-codegen", diff --git a/shopify_function/Cargo.toml b/shopify_function/Cargo.toml index 9df9075..5c59731 100644 --- a/shopify_function/Cargo.toml +++ b/shopify_function/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shopify_function" -version = "1.0.0" +version = "1.1.0" edition = "2021" authors = ["Surma ", "Delta Pham "] license = "MIT" @@ -8,7 +8,7 @@ description = "Crate to write Shopify Functions in Rust." [dependencies] serde_json = "1.0" -shopify_function_macro = { version = "1.0.0", path = "../shopify_function_macro" } +shopify_function_macro = { version = "1.1.0", path = "../shopify_function_macro" } shopify_function_wasm_api = "0.1.0" # Use the `small` feature of ryu (transitive dependency through serde_json) diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index 4ccc6d2..7494db9 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shopify_function_macro" -version = "1.0.0" +version = "1.1.0" edition = "2021" authors = ["Surma ", "Delta Pham "] license = "MIT" From 958246757056c9cdb937580484fe5ecaab8e3e83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 18:15:33 +0000 Subject: [PATCH 24/40] Bump flate2 from 1.1.1 to 1.1.2 Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.1.1 to 1.1.2. - [Release notes](https://github.com/rust-lang/flate2-rs/releases) - [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.1...1.1.2) --- updated-dependencies: - dependency-name: flate2 dependency-version: 1.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7e867a..c61db10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,9 +272,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", From 267b144cf7bb4f5b655620799f3296b608f5e1d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 19:39:18 +0000 Subject: [PATCH 25/40] Bump syn from 2.0.101 to 2.0.103 Bumps [syn](https://github.com/dtolnay/syn) from 2.0.101 to 2.0.103. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.101...2.0.103) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.103 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c61db10..2bf838e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1334,9 +1334,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", From 45f1665e566dbb9e3ccf0ef98d967b05d7b45e17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 19:49:51 +0000 Subject: [PATCH 26/40] Bump reqwest from 0.12.15 to 0.12.20 Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.15 to 0.12.20. - [Release notes](https://github.com/seanmonstar/reqwest/releases) - [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.15...v0.12.20) --- updated-dependencies: - dependency-name: reqwest dependency-version: 0.12.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 158 ++++++++++++++++++++--------------------------------- 1 file changed, 58 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c61db10..4f90801 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,7 +57,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -515,22 +515,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -698,6 +704,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "itertools" version = "0.14.0" @@ -966,9 +982,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64", "bytes", @@ -984,29 +1000,26 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows-registry", ] [[package]] @@ -1086,15 +1099,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.11.0" @@ -1490,6 +1494,24 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1693,29 +1715,29 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ + "windows-link", "windows-result", "windows-strings", - "windows-targets 0.53.0", ] [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -1726,7 +1748,7 @@ 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]] @@ -1735,7 +1757,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1744,30 +1766,14 @@ 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_i686_gnullvm 0.52.6", - "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", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -1776,96 +1782,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "wit-bindgen-rt" version = "0.39.0" From bcd8ac9efda5fb3db827fca249ae19b56b8d83e3 Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Wed, 18 Jun 2025 10:22:29 -0400 Subject: [PATCH 27/40] Bump `shopify_function_wasm_api` to `0.2.0` --- Cargo.lock | 5 +++-- shopify_function/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2bf838e..be3226a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1253,11 +1253,12 @@ dependencies = [ [[package]] name = "shopify_function_wasm_api" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57a2e64ef7d28cbe26bf591fd084093327d9d359e38355010720d818cd92ba9" +checksum = "cb7952650d134210fcd92b56a6cdc666a4ed5d0c56a8a21bf9113b62dee52d27" dependencies = [ "rmp-serde", + "seq-macro", "serde_json", "shopify_function_provider", "shopify_function_wasm_api_core", diff --git a/shopify_function/Cargo.toml b/shopify_function/Cargo.toml index 5c59731..5995522 100644 --- a/shopify_function/Cargo.toml +++ b/shopify_function/Cargo.toml @@ -9,7 +9,7 @@ description = "Crate to write Shopify Functions in Rust." [dependencies] serde_json = "1.0" shopify_function_macro = { version = "1.1.0", path = "../shopify_function_macro" } -shopify_function_wasm_api = "0.1.0" +shopify_function_wasm_api = "0.2.0" # Use the `small` feature of ryu (transitive dependency through serde_json) # to shave off ~9kb of the Wasm binary size. From 427be0548a2ccb418c0b16ef45ec470b95d52acc Mon Sep 17 00:00:00 2001 From: Adam Petro Date: Wed, 18 Jun 2025 10:35:24 -0400 Subject: [PATCH 28/40] v1.1.1 --- Cargo.lock | 4 ++-- shopify_function/Cargo.toml | 4 ++-- shopify_function_macro/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be3226a..a9b66a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1220,7 +1220,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "shopify_function" -version = "1.1.0" +version = "1.1.1" dependencies = [ "ryu", "serde_json", @@ -1230,7 +1230,7 @@ dependencies = [ [[package]] name = "shopify_function_macro" -version = "1.1.0" +version = "1.1.1" dependencies = [ "bluejay-core", "bluejay-typegen-codegen", diff --git a/shopify_function/Cargo.toml b/shopify_function/Cargo.toml index 5995522..40e6a8c 100644 --- a/shopify_function/Cargo.toml +++ b/shopify_function/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shopify_function" -version = "1.1.0" +version = "1.1.1" edition = "2021" authors = ["Surma ", "Delta Pham "] license = "MIT" @@ -8,7 +8,7 @@ description = "Crate to write Shopify Functions in Rust." [dependencies] serde_json = "1.0" -shopify_function_macro = { version = "1.1.0", path = "../shopify_function_macro" } +shopify_function_macro = { version = "1.1.1", path = "../shopify_function_macro" } shopify_function_wasm_api = "0.2.0" # Use the `small` feature of ryu (transitive dependency through serde_json) diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index 7494db9..22dd10b 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shopify_function_macro" -version = "1.1.0" +version = "1.1.1" edition = "2021" authors = ["Surma ", "Delta Pham "] license = "MIT" From b42e3032c91124bf2264ab03da705502295ff080 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 20:27:21 +0000 Subject: [PATCH 29/40] Bump syn from 2.0.103 to 2.0.104 Bumps [syn](https://github.com/dtolnay/syn) from 2.0.103 to 2.0.104. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.103...2.0.104) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.104 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e32dec..bc3d509 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1339,9 +1339,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.103" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", From a72cfefe00aa0369e047c2b55af79facb5d25cd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:55:08 +0000 Subject: [PATCH 30/40] Bump reqwest from 0.12.20 to 0.12.22 Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.20 to 0.12.22. - [Release notes](https://github.com/seanmonstar/reqwest/releases) - [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.20...v0.12.22) --- updated-dependencies: - dependency-name: reqwest dependency-version: 0.12.22 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc3d509..d10180e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -982,9 +982,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.20" +version = "0.12.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" +checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" dependencies = [ "base64", "bytes", From 1881a49f0ce2c8b8d26e90e329b187d96ea63be8 Mon Sep 17 00:00:00 2001 From: Andrew Hassan Date: Mon, 21 Jul 2025 11:48:22 -0400 Subject: [PATCH 31/40] Lint --- integration_tests/src/lib.rs | 14 ++++++-------- shopify_function/tests/derive_deserialize_test.rs | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index c7beb98..c652fa6 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -33,7 +33,7 @@ fn build_example(name: &str) -> Result<()> { } static FUNCTION_RUNNER_PATH: LazyLock> = LazyLock::new(|| { - let path = workspace_root().join(format!("tmp/function-runner-{}", FUNCTION_RUNNER_VERSION)); + let path = workspace_root().join(format!("tmp/function-runner-{FUNCTION_RUNNER_VERSION}")); if !path.exists() { std::fs::create_dir_all(workspace_root().join("tmp"))?; @@ -44,7 +44,7 @@ static FUNCTION_RUNNER_PATH: LazyLock> = LazyLock::new(| }); static TRAMPOLINE_PATH: LazyLock> = LazyLock::new(|| { - let path = workspace_root().join(format!("tmp/trampoline-{}", TRAMPOLINE_VERSION)); + let path = workspace_root().join(format!("tmp/trampoline-{TRAMPOLINE_VERSION}")); if !path.exists() { std::fs::create_dir_all(workspace_root().join("tmp"))?; download_trampoline(&path)?; @@ -56,8 +56,7 @@ fn download_function_runner(destination: &PathBuf) -> Result<()> { download_from_github( |target_arch, target_os| { format!( - "https://github.com/Shopify/function-runner/releases/download/v{}/function-runner-{}-{}-v{}.gz", - FUNCTION_RUNNER_VERSION, target_arch, target_os, FUNCTION_RUNNER_VERSION, + "https://github.com/Shopify/function-runner/releases/download/v{FUNCTION_RUNNER_VERSION}/function-runner-{target_arch}-{target_os}-v{FUNCTION_RUNNER_VERSION}.gz", ) }, destination, @@ -68,8 +67,7 @@ fn download_trampoline(destination: &PathBuf) -> Result<()> { download_from_github( |target_arch, target_os| { format!( - "https://github.com/Shopify/shopify-function-wasm-api/releases/download/shopify_function_trampoline/v{}/shopify-function-trampoline-{}-{}-v{}.gz", - TRAMPOLINE_VERSION, target_arch, target_os, TRAMPOLINE_VERSION, + "https://github.com/Shopify/shopify-function-wasm-api/releases/download/shopify_function_trampoline/v{TRAMPOLINE_VERSION}/shopify-function-trampoline-{target_arch}-{target_os}-v{TRAMPOLINE_VERSION}.gz", ) }, destination, @@ -127,10 +125,10 @@ pub fn prepare_example(name: &str) -> Result { build_example(name)?; let wasm_path = workspace_root() .join("target/wasm32-wasip1/release") - .join(format!("{}.wasm", name)); + .join(format!("{name}.wasm")); let trampolined_path = workspace_root() .join("target/wasm32-wasip1/release") - .join(format!("{}-trampolined.wasm", name)); + .join(format!("{name}-trampolined.wasm")); let trampoline_path = TRAMPOLINE_PATH .as_ref() .map_err(|e| anyhow::anyhow!("Failed to download trampoline: {}", e))?; diff --git a/shopify_function/tests/derive_deserialize_test.rs b/shopify_function/tests/derive_deserialize_test.rs index 0ff7b23..8c085c2 100644 --- a/shopify_function/tests/derive_deserialize_test.rs +++ b/shopify_function/tests/derive_deserialize_test.rs @@ -78,7 +78,7 @@ fn test_field_rename_takes_precedence_over_rename_all() { let input = TestStructWithRename::deserialize(&root_value).unwrap(); assert_eq!(input.field_one, "correct"); assert_eq!(input.field_two, 10); - assert_eq!(input.field_three, false); + assert!(!input.field_three); } #[derive(Deserialize, PartialEq, Debug)] From 1a164a467e9f9e50a568c33371206cff9b5d032b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 21:03:27 +0000 Subject: [PATCH 32/40] Bump serde_json from 1.0.140 to 1.0.141 --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.141 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d10180e..63aac63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1194,9 +1194,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", From 46c8e8e1c731824eeb6ab5a02d1811cb7afb1d0a Mon Sep 17 00:00:00 2001 From: Jeffrey Charles Date: Mon, 18 Aug 2025 11:57:23 -0400 Subject: [PATCH 33/40] Fix clippy issue with Configuration (#156) --- example_with_targets/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/example_with_targets/src/main.rs b/example_with_targets/src/main.rs index fa475d5..3b71c24 100644 --- a/example_with_targets/src/main.rs +++ b/example_with_targets/src/main.rs @@ -1,6 +1,7 @@ use shopify_function::prelude::*; use shopify_function::Result; +#[allow(dead_code)] #[derive(Deserialize)] #[shopify_function(rename_all = "camelCase")] struct Configuration {} From 47d50465540fdbfcc45a91fca148bd4d4ce60934 Mon Sep 17 00:00:00 2001 From: Jeffrey Charles Date: Mon, 18 Aug 2025 13:28:56 -0400 Subject: [PATCH 34/40] Update function-runner in integration tests (#155) --- integration_tests/src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index c652fa6..b322c64 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -6,7 +6,7 @@ use std::{ sync::LazyLock, }; -const FUNCTION_RUNNER_VERSION: &str = "8.0.0"; +const FUNCTION_RUNNER_VERSION: &str = "9.0.0"; const TRAMPOLINE_VERSION: &str = "1.0.0"; fn workspace_root() -> std::path::PathBuf { @@ -189,7 +189,7 @@ pub fn run_example( let mut output_bytes = Vec::new(); output.read_to_end(&mut output_bytes)?; - let output: serde_json::Value = serde_json::from_slice(&output_bytes)?; + let mut output: serde_json::Value = serde_json::from_slice(&output_bytes)?; if !status.success() { let logs = output @@ -205,10 +205,9 @@ pub fn run_example( ); } - let output_json_str = output - .get("output") - .and_then(|o| o.get("humanized").and_then(|h| h.as_str())) - .ok_or_else(|| anyhow::anyhow!("No output"))?; - let output_json: serde_json::Value = serde_json::from_str(output_json_str)?; + let output_json = output + .get_mut("output") + .ok_or_else(|| anyhow::anyhow!("No output"))? + .take(); Ok(output_json) } From 07763f714efa596479ab2b47a9742c5c2162f761 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 01:38:09 +0000 Subject: [PATCH 35/40] Bump anyhow from 1.0.98 to 1.0.99 Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.98 to 1.0.99. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.98...1.0.99) --- updated-dependencies: - dependency-name: anyhow dependency-version: 1.0.99 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63aac63..05c8cb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "ariadne" From 86e93e457f47d3d0f965ca10a591ea6ca5649b56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 02:34:22 +0000 Subject: [PATCH 36/40] Bump reqwest from 0.12.22 to 0.12.23 Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.22 to 0.12.23. - [Release notes](https://github.com/seanmonstar/reqwest/releases) - [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.22...v0.12.23) --- updated-dependencies: - dependency-name: reqwest dependency-version: 0.12.23 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63aac63..daf2c8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -982,9 +982,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.22" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64", "bytes", From 951f0884670544b81a1d47772d967c47c89e2c72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 02:43:56 +0000 Subject: [PATCH 37/40] Bump syn from 2.0.104 to 2.0.106 Bumps [syn](https://github.com/dtolnay/syn) from 2.0.104 to 2.0.106. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.104...2.0.106) --- updated-dependencies: - dependency-name: syn dependency-version: 2.0.106 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63aac63..c8528c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1339,9 +1339,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", From fb0e3cb4b76e3b029e1b7dd8092af1d49d0550e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:43:32 +0000 Subject: [PATCH 38/40] Bump actions/checkout from 4.2.2 to 5.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/11bd71901bbe5b1630ceea73d27597364c9af683...08c6903cd8c0fde910a37f88322edcfb5dd907a8) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 062b5df..f06d3d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Run cargo fmt run: cargo fmt --check - name: Run clippy @@ -24,13 +24,13 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Run tests run: cargo test build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Build run: cargo build --release From a976f941680551de93bd5e730581525297ceda88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:43:44 +0000 Subject: [PATCH 39/40] Bump proc-macro2 from 1.0.95 to 1.0.101 Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.95 to 1.0.101. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.95...1.0.101) --- updated-dependencies: - dependency-name: proc-macro2 dependency-version: 1.0.101 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- shopify_function_macro/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0dd3411..738f9af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -952,9 +952,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] diff --git a/shopify_function_macro/Cargo.toml b/shopify_function_macro/Cargo.toml index 22dd10b..70427c0 100644 --- a/shopify_function_macro/Cargo.toml +++ b/shopify_function_macro/Cargo.toml @@ -12,7 +12,7 @@ proc-macro = true [dependencies] syn = { version = "2.0", features = ["full"] } quote = "1.0" -proc-macro2 = "1.0.94" +proc-macro2 = "1.0.101" bluejay-typegen-codegen = "0.3.1" bluejay-core = "0.3.1" convert_case = "0.8" From b86d47148c69f683ab6dc343da10bc1ae20703b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:44:19 +0000 Subject: [PATCH 40/40] Bump serde_json from 1.0.141 to 1.0.142 Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.141 to 1.0.142. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.141...v1.0.142) --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.142 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0dd3411..de160ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1194,9 +1194,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr",