From 5082a0d17b3ecf3311538eb5240efdf666922d10 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 7 Jun 2023 12:50:18 +0200 Subject: [PATCH 01/32] Do not render PayPal subscription button if no plan is connected --- .../ContextBootstrap/SingleProductBootstap.js | 3 +- modules/ppcp-button/services.php | 1 - .../ppcp-button/src/Assets/SmartButton.php | 34 +-------- modules/ppcp-subscription/services.php | 2 +- .../src/Helper/SubscriptionHelper.php | 69 +++++++++++++++++++ modules/ppcp-wc-gateway/services.php | 3 +- .../src/Checkout/DisableGateways.php | 23 +++++-- 7 files changed, 94 insertions(+), 41 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 376962772..2237eb2b1 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -59,7 +59,8 @@ class SingleProductBootstap { shouldRender() { return document.querySelector('form.cart') !== null && !this.priceAmountIsZero() - && !this.isSubscriptionMode(); + && !this.isSubscriptionMode() + && PayPalCommerceGateway.subscription_plan_id !== ''; } priceAmount() { diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index 7f8c50b14..9296f1fd0 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -15,7 +15,6 @@ use WooCommerce\PayPalCommerce\Button\Helper\CheckoutFormSaver; use WooCommerce\PayPalCommerce\Button\Endpoint\SaveCheckoutFormEndpoint; use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator; use WooCommerce\PayPalCommerce\Button\Endpoint\ValidateCheckoutEndpoint; -use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\Button\Assets\DisabledSmartButton; use WooCommerce\PayPalCommerce\Button\Assets\SmartButton; diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 7f07c332a..ff2472df2 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -850,7 +850,7 @@ class SmartButton implements SmartButtonInterface { 'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ), ), ), - 'subscription_plan_id' => $this->paypal_subscription_id(), + 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), 'enforce_vault' => $this->has_subscriptions(), 'can_save_vault_token' => $this->can_save_vault_token(), 'is_free_trial_cart' => $is_free_trial_cart, @@ -1383,38 +1383,6 @@ class SmartButton implements SmartButtonInterface { return false; } - /** - * Returns PayPal subscription plan id from WC subscription product. - * - * @return string - */ - private function paypal_subscription_id(): string { - if ( $this->subscription_helper->current_product_is_subscription() ) { - $product = wc_get_product(); - assert( $product instanceof WC_Product ); - - if ( $product->get_type() === 'subscription' && $product->meta_exists( 'ppcp_subscription_plan' ) ) { - return $product->get_meta( 'ppcp_subscription_plan' )['id']; - } - } - - $cart = WC()->cart ?? null; - if ( ! $cart || $cart->is_empty() ) { - return ''; - } - $items = $cart->get_cart_contents(); - foreach ( $items as $item ) { - $product = wc_get_product( $item['product_id'] ); - assert( $product instanceof WC_Product ); - - if ( $product->get_type() === 'subscription' && $product->meta_exists( 'ppcp_subscription_plan' ) ) { - return $product->get_meta( 'ppcp_subscription_plan' )['id']; - } - } - - return ''; - } - /** * Returns the intent. * diff --git a/modules/ppcp-subscription/services.php b/modules/ppcp-subscription/services.php index b9ce27543..1424725b2 100644 --- a/modules/ppcp-subscription/services.php +++ b/modules/ppcp-subscription/services.php @@ -15,7 +15,7 @@ use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; return array( 'subscription.helper' => static function ( ContainerInterface $container ): SubscriptionHelper { - return new SubscriptionHelper(); + return new SubscriptionHelper( $container->get( 'wcgateway.settings' ) ); }, 'subscription.renewal-handler' => static function ( ContainerInterface $container ): RenewalHandler { $logger = $container->get( 'woocommerce.logger.woocommerce' ); diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index 286fc2bc1..1e9a009b4 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -13,12 +13,30 @@ namespace WooCommerce\PayPalCommerce\Subscription\Helper; use WC_Product; use WC_Subscriptions_Product; +use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; /** * Class SubscriptionHelper */ class SubscriptionHelper { + /** + * The settings. + * + * @var Settings + */ + private $settings; + + /** + * SubscriptionHelper constructor. + * + * @param Settings $settings The settings. + */ + public function __construct( Settings $settings ) { + $this->settings = $settings; + } + /** * Whether the current product is a subscription. * @@ -150,4 +168,55 @@ class SubscriptionHelper { return false; } + + /** + * Checks if subscription product is allowed. + * + * @return bool + * @throws NotFoundException If setting is not found. + */ + public function checkout_subscription_product_allowed(): bool { + $subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : ''; + if ( + $subscription_mode !== 'subscriptions_api' + || ! $this->cart_contains_subscription() + || ! $this->paypal_subscription_id() + ) { + return false; + } + + return true; + } + + /** + * Returns PayPal subscription plan id from WC subscription product. + * + * @return string + */ + public function paypal_subscription_id(): string { + if ( $this->current_product_is_subscription() ) { + $product = wc_get_product(); + assert( $product instanceof WC_Product ); + + if ( $product->get_type() === 'subscription' && $product->meta_exists( 'ppcp_subscription_plan' ) ) { + return $product->get_meta( 'ppcp_subscription_plan' )['id']; + } + } + + $cart = WC()->cart ?? null; + if ( ! $cart || $cart->is_empty() ) { + return ''; + } + $items = $cart->get_cart_contents(); + foreach ( $items as $item ) { + $product = wc_get_product( $item['product_id'] ); + assert( $product instanceof WC_Product ); + + if ( $product->get_type() === 'subscription' && $product->meta_exists( 'ppcp_subscription_plan' ) ) { + return $product->get_meta( 'ppcp_subscription_plan' )['id']; + } + } + + return ''; + } } diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 901c1f94a..9025bf9e1 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -148,7 +148,8 @@ return array( $session_handler = $container->get( 'session.handler' ); $settings = $container->get( 'wcgateway.settings' ); $settings_status = $container->get( 'wcgateway.settings.status' ); - return new DisableGateways( $session_handler, $settings, $settings_status ); + $subscription_helper = $container->get( 'subscription.helper' ); + return new DisableGateways( $session_handler, $settings, $settings_status, $subscription_helper ); }, 'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool { diff --git a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php index bbd9b30d3..6342727a5 100644 --- a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php +++ b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway\Checkout; use WooCommerce\PayPalCommerce\Session\SessionHandler; +use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; @@ -42,22 +43,32 @@ class DisableGateways { */ protected $settings_status; + /** + * The subscription helper. + * + * @var SubscriptionHelper + */ + private $subscription_helper; + /** * DisableGateways constructor. * * @param SessionHandler $session_handler The Session Handler. * @param ContainerInterface $settings The Settings. * @param SettingsStatus $settings_status The Settings status helper. + * @param SubscriptionHelper $subscription_helper The subscription helper. */ public function __construct( SessionHandler $session_handler, ContainerInterface $settings, - SettingsStatus $settings_status + SettingsStatus $settings_status, + SubscriptionHelper $subscription_helper ) { - $this->session_handler = $session_handler; - $this->settings = $settings; - $this->settings_status = $settings_status; + $this->session_handler = $session_handler; + $this->settings = $settings; + $this->settings_status = $settings_status; + $this->subscription_helper = $subscription_helper; } /** @@ -113,6 +124,10 @@ class DisableGateways { return true; } + if ( is_checkout() && ! $this->subscription_helper->checkout_subscription_product_allowed() ) { + return true; + } + return false; } From 21fd894d7aa01c333a762b20b33590eb85fa0cfd Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 7 Jun 2023 14:43:32 +0200 Subject: [PATCH 02/32] Check if subscription product in cart before removing PayPal button --- modules/ppcp-subscription/src/Helper/SubscriptionHelper.php | 1 - modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index 1e9a009b4..8b3034acd 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -179,7 +179,6 @@ class SubscriptionHelper { $subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : ''; if ( $subscription_mode !== 'subscriptions_api' - || ! $this->cart_contains_subscription() || ! $this->paypal_subscription_id() ) { return false; diff --git a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php index 6342727a5..e5078ae3f 100644 --- a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php +++ b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php @@ -124,7 +124,11 @@ class DisableGateways { return true; } - if ( is_checkout() && ! $this->subscription_helper->checkout_subscription_product_allowed() ) { + if ( + is_checkout() + && $this->subscription_helper->cart_contains_subscription() + && ! $this->subscription_helper->checkout_subscription_product_allowed() + ) { return true; } From c570621b67236e745df1e0c58da4091962c91de6 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 8 Jun 2023 12:39:08 +0200 Subject: [PATCH 03/32] Add script for disabling subscription product form fields --- .../resources/js/order-edit-page.js | 2 +- modules/ppcp-subscription/.babelrc | 11 + modules/ppcp-subscription/.gitignore | 2 + modules/ppcp-subscription/package.json | 31 + .../resources/js/paypal-subscription.js | 20 + modules/ppcp-subscription/services.php | 11 + .../src/SubscriptionModule.php | 39 + modules/ppcp-subscription/webpack.config.js | 35 + modules/ppcp-subscription/yarn.lock | 2185 +++++++++++++++++ package.json | 3 + 10 files changed, 2338 insertions(+), 1 deletion(-) create mode 100644 modules/ppcp-subscription/.babelrc create mode 100644 modules/ppcp-subscription/.gitignore create mode 100644 modules/ppcp-subscription/package.json create mode 100644 modules/ppcp-subscription/resources/js/paypal-subscription.js create mode 100644 modules/ppcp-subscription/webpack.config.js create mode 100644 modules/ppcp-subscription/yarn.lock diff --git a/modules/ppcp-order-tracking/resources/js/order-edit-page.js b/modules/ppcp-order-tracking/resources/js/order-edit-page.js index a49717d8c..745ca529d 100644 --- a/modules/ppcp-order-tracking/resources/js/order-edit-page.js +++ b/modules/ppcp-order-tracking/resources/js/order-edit-page.js @@ -3,7 +3,7 @@ document.addEventListener( () => { const config = PayPalCommerceGatewayOrderTrackingInfo; if (!typeof (PayPalCommerceGatewayOrderTrackingInfo)) { - console.error('trackign cannot be set.'); + console.error('tracking cannot be set.'); return; } diff --git a/modules/ppcp-subscription/.babelrc b/modules/ppcp-subscription/.babelrc new file mode 100644 index 000000000..9e972c8b9 --- /dev/null +++ b/modules/ppcp-subscription/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "useBuiltIns": "usage", + "corejs": "3.25.0" + } + ] + ] +} diff --git a/modules/ppcp-subscription/.gitignore b/modules/ppcp-subscription/.gitignore new file mode 100644 index 000000000..265c2208c --- /dev/null +++ b/modules/ppcp-subscription/.gitignore @@ -0,0 +1,2 @@ +node_modules +assets diff --git a/modules/ppcp-subscription/package.json b/modules/ppcp-subscription/package.json new file mode 100644 index 000000000..9fd2f9305 --- /dev/null +++ b/modules/ppcp-subscription/package.json @@ -0,0 +1,31 @@ +{ + "name": "ppcp-subscription", + "version": "1.0.0", + "license": "GPL-3.0-or-later", + "browserslist": [ + "> 0.5%", + "Safari >= 8", + "Chrome >= 41", + "Firefox >= 43", + "Edge >= 14" + ], + "dependencies": { + "core-js": "^3.25.0" + }, + "devDependencies": { + "@babel/core": "^7.19", + "@babel/preset-env": "^7.19", + "babel-loader": "^8.2", + "cross-env": "^7.0.3", + "file-loader": "^6.2.0", + "sass": "^1.42.1", + "sass-loader": "^12.1.0", + "webpack": "^5.76", + "webpack-cli": "^4.10" + }, + "scripts": { + "build": "cross-env BABEL_ENV=default NODE_ENV=production webpack", + "watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch", + "dev": "cross-env BABEL_ENV=default webpack --watch" + } +} diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js new file mode 100644 index 000000000..3e0ee6a70 --- /dev/null +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -0,0 +1,20 @@ +document.addEventListener( + 'DOMContentLoaded', + () => { + if(PayPalCommerceGatewayPayPalSubscription.product_connected === 'yes') { + const periodInterval = document.querySelector('#_subscription_period_interval'); + periodInterval.setAttribute('disabled', 'disabled'); + + const subscriptionPeriod = document.querySelector('#_subscription_period'); + subscriptionPeriod.setAttribute('disabled', 'disabled'); + + const subscriptionLength = document.querySelector('#_subscription_length'); + subscriptionLength.setAttribute('disabled', 'disabled'); + + const subscriptionTrialLength = document.querySelector('#_subscription_trial_length'); + subscriptionTrialLength.setAttribute('disabled', 'disabled'); + + const subscriptionTrialPeriod = document.querySelector('#_subscription_trial_period'); + subscriptionTrialPeriod.setAttribute('disabled', 'disabled'); + } + }); diff --git a/modules/ppcp-subscription/services.php b/modules/ppcp-subscription/services.php index 1424725b2..d3bb5e130 100644 --- a/modules/ppcp-subscription/services.php +++ b/modules/ppcp-subscription/services.php @@ -54,4 +54,15 @@ return array( $container->get( 'woocommerce.logger.woocommerce' ) ); }, + 'subscription.module.url' => static function ( ContainerInterface $container ): string { + /** + * The path cannot be false. + * + * @psalm-suppress PossiblyFalseArgument + */ + return plugins_url( + '/modules/ppcp-subscription/', + dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php' + ); + }, ); diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 099ee18ff..00ae5b516 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -155,6 +155,45 @@ class SubscriptionModule implements ModuleInterface { if ( defined( 'PPCP_FLAG_SUBSCRIPTIONS_API' ) && PPCP_FLAG_SUBSCRIPTIONS_API ) { $this->subscriptions_api_integration( $c ); } + + add_action( + 'admin_enqueue_scripts', + function( $hook ) use ( $c ) { + $settings = $c->get( 'wcgateway.settings' ); + $subscription_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; + if ( $hook !== 'post.php' || $subscription_mode !== 'subscriptions_api' ) { + return; + } + + $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); + $product = wc_get_product( $post_id ); + if ( ! is_a( $product, WC_Product::class ) ) { + return; + } + + $subscription_product_connected = $product->get_meta( '_ppcp_enable_subscription_product' ); + if ( $subscription_product_connected !== 'yes' ) { + return; + } + + $module_url = $c->get( 'subscription.module.url' ); + wp_enqueue_script( + 'ppcp-paypal-subscription', + untrailingslashit( $module_url ) . '/assets/js/paypal-subscription.js', + array( 'jquery' ), + $c->get( 'ppcp.asset-version' ), + true + ); + + wp_localize_script( + 'ppcp-paypal-subscription', + 'PayPalCommerceGatewayPayPalSubscription', + array( + 'product_connected' => $subscription_product_connected, + ) + ); + } + ); } /** diff --git a/modules/ppcp-subscription/webpack.config.js b/modules/ppcp-subscription/webpack.config.js new file mode 100644 index 000000000..4a5f4a0fc --- /dev/null +++ b/modules/ppcp-subscription/webpack.config.js @@ -0,0 +1,35 @@ +const path = require('path'); +const isProduction = process.env.NODE_ENV === 'production'; + +module.exports = { + devtool: isProduction ? 'source-map' : 'eval-source-map', + mode: isProduction ? 'production' : 'development', + target: 'web', + entry: { + 'paypal-subscription': path.resolve('./resources/js/paypal-subscription.js'), + }, + output: { + path: path.resolve(__dirname, 'assets/'), + filename: 'js/[name].js', + }, + module: { + rules: [{ + test: /\.js?$/, + exclude: /node_modules/, + loader: 'babel-loader', + }, + { + test: /\.scss$/, + exclude: /node_modules/, + use: [ + { + loader: 'file-loader', + options: { + name: 'css/[name].css', + } + }, + {loader:'sass-loader'} + ] + }] + } +}; diff --git a/modules/ppcp-subscription/yarn.lock b/modules/ppcp-subscription/yarn.lock new file mode 100644 index 000000000..08b8761f0 --- /dev/null +++ b/modules/ppcp-subscription/yarn.lock @@ -0,0 +1,2185 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.22.0", "@babel/compat-data@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.3.tgz#cd502a6a0b6e37d7ad72ce7e71a7160a3ae36f7e" + integrity sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ== + +"@babel/core@^7.19": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.1.tgz#5de51c5206f4c6f5533562838337a603c1033cfd" + integrity sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.22.0" + "@babel/helper-compilation-targets" "^7.22.1" + "@babel/helper-module-transforms" "^7.22.1" + "@babel/helpers" "^7.22.0" + "@babel/parser" "^7.22.0" + "@babel/template" "^7.21.9" + "@babel/traverse" "^7.22.1" + "@babel/types" "^7.22.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/generator@^7.22.0", "@babel/generator@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.3.tgz#0ff675d2edb93d7596c5f6728b52615cfc0df01e" + integrity sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A== + dependencies: + "@babel/types" "^7.22.3" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.3.tgz#c9b83d1ba74e163e023f008a3d3204588a7ceb60" + integrity sha512-ahEoxgqNoYXm0k22TvOke48i1PkavGu0qGCmcq9ugi6gnmvKNaMjKBSrZTnWUi1CFEeNAUiVba0Wtzm03aSkJg== + dependencies: + "@babel/types" "^7.22.3" + +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz#bfcd6b7321ffebe33290d68550e2c9d7eb7c7a58" + integrity sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ== + dependencies: + "@babel/compat-data" "^7.22.0" + "@babel/helper-validator-option" "^7.21.0" + browserslist "^4.21.3" + lru-cache "^5.1.1" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.21.0", "@babel/helper-create-class-features-plugin@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.1.tgz#ae3de70586cc757082ae3eba57240d42f468c41b" + integrity sha512-SowrZ9BWzYFgzUMwUmowbPSGu6CXL5MSuuCkG3bejahSpSymioPmuLdhPxNOc9MjuNGjy7M/HaXvJ8G82Lywlw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.22.1" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-member-expression-to-functions" "^7.22.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.22.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/helper-split-export-declaration" "^7.18.6" + semver "^6.3.0" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.1.tgz#a7ed9a8488b45b467fca353cd1a44dc5f0cf5c70" + integrity sha512-WWjdnfR3LPIe+0EY8td7WmjhytxXtjKAEpnAxun/hkNiyOaPlvGK+NZaBFIdi9ndYV3Gav7BpFvtUwnaJlwi1w== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.3.1" + semver "^6.3.0" + +"@babel/helper-define-polyfill-provider@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.0.tgz#487053f103110f25b9755c5980e031e93ced24d8" + integrity sha512-RnanLx5ETe6aybRi1cO/edaRH+bNYWaryCEmjDDYyNr4wnSzyOp8T0dWipmqVHKEY3AbVKUom50AKSlj1zmKbg== + dependencies: + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz#ac3a56dbada59ed969d712cf527bd8271fe3eba8" + integrity sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA== + +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" + integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== + dependencies: + "@babel/template" "^7.20.7" + "@babel/types" "^7.21.0" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.22.0": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.3.tgz#4b77a12c1b4b8e9e28736ed47d8b91f00976911f" + integrity sha512-Gl7sK04b/2WOb6OPVeNy9eFKeD3L6++CzL3ykPOWqTn08xgYYK0wz4TUh2feIImDXxcVW3/9WQ1NMKY66/jfZA== + dependencies: + "@babel/types" "^7.22.3" + +"@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.21.4": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" + integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg== + dependencies: + "@babel/types" "^7.21.4" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.5", "@babel/helper-module-transforms@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.1.tgz#e0cad47fedcf3cae83c11021696376e2d5a50c63" + integrity sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.1" + "@babel/helper-module-imports" "^7.21.4" + "@babel/helper-simple-access" "^7.21.5" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.21.9" + "@babel/traverse" "^7.22.1" + "@babel/types" "^7.22.0" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.21.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" + integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== + +"@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7", "@babel/helper-replace-supers@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.1.tgz#38cf6e56f7dc614af63a21b45565dd623f0fdc95" + integrity sha512-ut4qrkE4AuSfrwHSps51ekR1ZY/ygrP1tp0WFm8oVq6nzc/hvfV/22JylndIbsf2U2M9LOMwiSddr6y+78j+OQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.1" + "@babel/helper-member-expression-to-functions" "^7.22.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/template" "^7.21.9" + "@babel/traverse" "^7.22.1" + "@babel/types" "^7.22.0" + +"@babel/helper-simple-access@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz#d697a7971a5c39eac32c7e63c0921c06c8a249ee" + integrity sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg== + dependencies: + "@babel/types" "^7.21.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" + integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== + dependencies: + "@babel/types" "^7.20.0" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz#2b3eea65443c6bdc31c22d037c65f6d323b6b2bd" + integrity sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-option@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" + integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== + +"@babel/helper-wrap-function@^7.18.9": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" + integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== + dependencies: + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.20.5" + "@babel/types" "^7.20.5" + +"@babel/helpers@^7.22.0": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.3.tgz#53b74351da9684ea2f694bf0877998da26dd830e" + integrity sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w== + dependencies: + "@babel/template" "^7.21.9" + "@babel/traverse" "^7.22.1" + "@babel/types" "^7.22.3" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.21.9", "@babel/parser@^7.22.0", "@babel/parser@^7.22.4": + version "7.22.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.4.tgz#a770e98fd785c231af9d93f6459d36770993fb32" + integrity sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.3.tgz#a75be1365c0c3188c51399a662168c1c98108659" + integrity sha512-6r4yRwEnorYByILoDRnEqxtojYKuiIv9FojW2E8GUKo9eWBwbKcd9IiZOZpdyXc64RmyGGyPu3/uAcrz/dq2kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/plugin-transform-optional-chaining" "^7.22.3" + +"@babel/plugin-proposal-private-property-in-object@^7.21.0": + version "7.21.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz#69d597086b6760c4126525cfa154f34631ff272c" + integrity sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" + integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-syntax-import-attributes@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.3.tgz#d7168f22b9b49a6cc1792cec78e06a18ad2e7b4b" + integrity sha512-i35jZJv6aO7hxEbIWQ41adVfOzjm9dcYDNeWlBMd8p0ZQRtNUCBrmGwZt+H5lb+oOC9a3svp956KP0oWGA1YsA== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.21.5.tgz#9bb42a53de447936a57ba256fbf537fc312b6929" + integrity sha512-wb1mhwGOCaXHDTcsRYMKF9e5bbMgqwxtqa2Y1ifH96dXJPwbuLX9qHy3clhrxVqgMz7nyNXs8VkxdH8UBcjKqA== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-async-generator-functions@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.3.tgz#3ed99924c354fb9e80dabb2cc8d002c702e94527" + integrity sha512-36A4Aq48t66btydbZd5Fk0/xJqbpg/v4QWI4AH4cYHBXy9Mu42UOupZpebKFiCFNT9S9rJFcsld0gsv0ayLjtA== + dependencies: + "@babel/helper-environment-visitor" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" + integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-remap-async-to-generator" "^7.18.9" + +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoping@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz#e737b91037e5186ee16b76e7ae093358a5634f02" + integrity sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-class-properties@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.3.tgz#3407145e513830df77f0cef828b8b231c166fe4c" + integrity sha512-mASLsd6rhOrLZ5F3WbCxkzl67mmOnqik0zrg5W6D/X0QMW7HtvnoL1dRARLKIbMP3vXwkwziuLesPqWVGIl6Bw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-class-static-block@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.3.tgz#e352cf33567385c731a8f21192efeba760358773" + integrity sha512-5BirgNWNOx7cwbTJCOmKFJ1pZjwk5MUfMIwiBBvsirCJMZeQgs5pk6i1OlkVg+1Vef5LfBahFOrdCnAWvkVKMw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz#f469d0b07a4c5a7dbb21afad9e27e57b47031665" + integrity sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-split-export-declaration" "^7.18.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.21.5.tgz#3a2d8bb771cd2ef1cd736435f6552fe502e11b44" + integrity sha512-TR653Ki3pAwxBxUe8srfF3e4Pe3FTA46uaNHYyQwIoM4oWKSoOZiDNyHJ0oIoDIUPSRQbQG7jzgVBX3FPVne1Q== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/template" "^7.20.7" + +"@babel/plugin-transform-destructuring@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz#73b46d0fd11cd6ef57dea8a381b1215f4959d401" + integrity sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" + integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-dynamic-import@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.1.tgz#6c56afaf896a07026330cf39714532abed8d9ed1" + integrity sha512-rlhWtONnVBPdmt+jeewS0qSnMz/3yLFrqAP8hHC6EDcrYRSyuz9f9yQhHvVn2Ad6+yO9fHXac5piudeYrInxwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-export-namespace-from@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.3.tgz#9b8700aa495007d3bebac8358d1c562434b680b9" + integrity sha512-5Ti1cHLTDnt3vX61P9KZ5IG09bFXp4cDVFJIAeCZuxu9OXXJJZp5iP0n/rzM2+iAutJY+KWEyyHcRaHlpQ/P5g== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.5.tgz#e890032b535f5a2e237a18535f56a9fdaa7b83fc" + integrity sha512-nYWpjKW/7j/I/mZkGVgHJXh4bA1sfdFnJoOXwJuj4m3Q2EraO/8ZyrkCau9P5tbHQk01RMSt6KYLCsW7730SXQ== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== + dependencies: + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-json-strings@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.3.tgz#a181b8679cf7c93e9d0e3baa5b1776d65be601a9" + integrity sha512-IuvOMdeOOY2X4hRNAT6kwbePtK21BUyrAEgLKviL8pL6AEEVUVcqtRdN/HJXBLGIbt9T3ETmXRnFedRRmQNTYw== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-logical-assignment-operators@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.3.tgz#9e021455810f33b0baccb82fb759b194f5dc36f0" + integrity sha512-CbayIfOw4av2v/HYZEsH+Klks3NC2/MFIR3QR8gnpGNNPEaq2fdlVCRYG/paKs7/5hvBLQ+H70pGWOHtlNEWNA== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-amd@^7.20.11": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz#3daccca8e4cc309f03c3a0c4b41dc4b26f55214a" + integrity sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g== + dependencies: + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-transform-modules-commonjs@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.5.tgz#d69fb947eed51af91de82e4708f676864e5e47bc" + integrity sha512-OVryBEgKUbtqMoB7eG2rs6UFexJi6Zj6FDXx+esBLPTCxCNxAY9o+8Di7IsUGJ+AVhp5ncK0fxWUBd0/1gPhrQ== + dependencies: + "@babel/helper-module-transforms" "^7.21.5" + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/helper-simple-access" "^7.21.5" + +"@babel/plugin-transform-modules-systemjs@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.3.tgz#cc507e03e88d87b016feaeb5dae941e6ef50d91e" + integrity sha512-V21W3bKLxO3ZjcBJZ8biSvo5gQ85uIXW2vJfh7JSWf/4SLUSr1tOoHX3ruN4+Oqa2m+BKfsxTR1I+PsvkIWvNw== + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/helper-validator-identifier" "^7.19.1" + +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.3.tgz#db6fb77e6b3b53ec3b8d370246f0b7cf67d35ab4" + integrity sha512-c6HrD/LpUdNNJsISQZpds3TXvfYIAbo+efE9aWmY/PmSRD0agrJ9cPMt4BmArwUQ7ZymEWTFjTyp+yReLJZh0Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-new-target@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.3.tgz#deb0377d741cbee2f45305868b9026dcd6dd96e2" + integrity sha512-5RuJdSo89wKdkRTqtM9RVVJzHum9c2s0te9rB7vZC1zKKxcioWIy+xcu4OoIAjyFZhb/bp5KkunuLin1q7Ct+w== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.3.tgz#8c519f8bf5af94a9ca6f65cf422a9d3396e542b9" + integrity sha512-CpaoNp16nX7ROtLONNuCyenYdY/l7ZsR6aoVa7rW7nMWisoNoQNIH5Iay/4LDyRjKMuElMqXiBoOQCDLTMGZiw== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.3.tgz#02493070ca6685884b0eee705363ee4da2132ab0" + integrity sha512-+AF88fPDJrnseMh5vD9+SH6wq4ZMvpiTMHh58uLs+giMEyASFVhcT3NkoyO+NebFCNnpHJEq5AXO2txV4AGPDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.3.tgz#da6fba693effb8c203d8c3bdf7bf4e2567e802e9" + integrity sha512-38bzTsqMMCI46/TQnJwPPpy33EjLCc1Gsm2hRTF6zTMWnKsN61vdrpuzIEGQyKEhDSYDKyZHrrd5FMj4gcUHhw== + dependencies: + "@babel/compat-data" "^7.22.3" + "@babel/helper-compilation-targets" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.22.3" + +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-optional-catch-binding@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.3.tgz#e971a083fc7d209d9cd18253853af1db6d8dc42f" + integrity sha512-bnDFWXFzWY0BsOyqaoSXvMQ2F35zutQipugog/rqotL2S4ciFOKlRYUu9djt4iq09oh2/34hqfRR2k1dIvuu4g== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.3.tgz#5fd24a4a7843b76da6aeec23c7f551da5d365290" + integrity sha512-63v3/UFFxhPKT8j8u1jTTGVyITxl7/7AfOqK8C5gz1rHURPUGe3y5mvIf68eYKGoBNahtJnTxBKug4BQOnzeJg== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.3.tgz#24477acfd2fd2bc901df906c9bf17fbcfeee900d" + integrity sha512-x7QHQJHPuD9VmfpzboyGJ5aHEr9r7DsAsdxdhJiTB3J3j8dyl+NFZ+rX5Q2RWFDCs61c06qBfS4ys2QYn8UkMw== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-private-methods@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.3.tgz#adac38020bab5047482d3297107c1f58e9c574f6" + integrity sha512-fC7jtjBPFqhqpPAE+O4LKwnLq7gGkD3ZmC2E3i4qWH34mH3gOg2Xrq5YMHUq6DM30xhqM1DNftiRaSqVjEG+ug== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-private-property-in-object@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.3.tgz#031621b02c7b7d95389de1a3dba2fe9e8c548e56" + integrity sha512-C7MMl4qWLpgVCbXfj3UW8rR1xeCnisQ0cU7YJHV//8oNBS0aCIVg1vFnZXxOckHhEpQyqNNkWmvSEWnMLlc+Vw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.21.5.tgz#576c62f9923f94bcb1c855adc53561fd7913724e" + integrity sha512-ZoYBKDb6LyMi5yCsByQ5jmXsHAQDDYeexT1Szvlmui+lADvfSecr5Dxd/PkrTC3pAD182Fcju1VQkB4oCp9M+w== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + regenerator-transform "^0.15.1" + +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz#c2d83e0b99d3bf83e07b11995ee24bf7ca09401e" + integrity sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" + integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-escapes@^7.21.5": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.21.5.tgz#1e55ed6195259b0e9061d81f5ef45a9b009fb7f2" + integrity sha512-LYm/gTOwZqsYohlvFUe/8Tujz75LqqVC2w+2qPHLR+WyWHGCZPN1KBpJCJn+4Bk4gOkQy/IXKIge6az5MqwlOg== + dependencies: + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-unicode-property-regex@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.3.tgz#597b6a614dc93eaae605ee293e674d79d32eb380" + integrity sha512-5ScJ+OmdX+O6HRuMGW4kv7RL9vIKdtdAj9wuWUKy1wbHY3jaM/UlyIiC1G7J6UJiiyMukjjK0QwL3P0vBd0yYg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-unicode-sets-regex@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.3.tgz#7c14ee33fa69782b0101d0f7143d3fc73ce00700" + integrity sha512-hNufLdkF8vqywRp+P55j4FHXqAX2LRUccoZHH7AFn1pq5ZOO2ISKW9w13bFZVjBoTqeve2HOgoJCcaziJVhGNw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + +"@babel/preset-env@^7.19": + version "7.22.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.4.tgz#c86a82630f0e8c61d9bb9327b7b896732028cbed" + integrity sha512-c3lHOjbwBv0TkhYCr+XCR6wKcSZ1QbQTVdSkZUaVpLv8CVWotBMArWUi5UAJrcrQaEnleVkkvaV8F/pmc/STZQ== + dependencies: + "@babel/compat-data" "^7.22.3" + "@babel/helper-compilation-targets" "^7.22.1" + "@babel/helper-plugin-utils" "^7.21.5" + "@babel/helper-validator-option" "^7.21.0" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.3" + "@babel/plugin-proposal-private-property-in-object" "^7.21.0" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.20.0" + "@babel/plugin-syntax-import-attributes" "^7.22.3" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.21.5" + "@babel/plugin-transform-async-generator-functions" "^7.22.3" + "@babel/plugin-transform-async-to-generator" "^7.20.7" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.21.0" + "@babel/plugin-transform-class-properties" "^7.22.3" + "@babel/plugin-transform-class-static-block" "^7.22.3" + "@babel/plugin-transform-classes" "^7.21.0" + "@babel/plugin-transform-computed-properties" "^7.21.5" + "@babel/plugin-transform-destructuring" "^7.21.3" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-dynamic-import" "^7.22.1" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-export-namespace-from" "^7.22.3" + "@babel/plugin-transform-for-of" "^7.21.5" + "@babel/plugin-transform-function-name" "^7.18.9" + "@babel/plugin-transform-json-strings" "^7.22.3" + "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-logical-assignment-operators" "^7.22.3" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.20.11" + "@babel/plugin-transform-modules-commonjs" "^7.21.5" + "@babel/plugin-transform-modules-systemjs" "^7.22.3" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.3" + "@babel/plugin-transform-new-target" "^7.22.3" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.3" + "@babel/plugin-transform-numeric-separator" "^7.22.3" + "@babel/plugin-transform-object-rest-spread" "^7.22.3" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-optional-catch-binding" "^7.22.3" + "@babel/plugin-transform-optional-chaining" "^7.22.3" + "@babel/plugin-transform-parameters" "^7.22.3" + "@babel/plugin-transform-private-methods" "^7.22.3" + "@babel/plugin-transform-private-property-in-object" "^7.22.3" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.21.5" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.20.7" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.9" + "@babel/plugin-transform-typeof-symbol" "^7.18.9" + "@babel/plugin-transform-unicode-escapes" "^7.21.5" + "@babel/plugin-transform-unicode-property-regex" "^7.22.3" + "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/plugin-transform-unicode-sets-regex" "^7.22.3" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.22.4" + babel-plugin-polyfill-corejs2 "^0.4.3" + babel-plugin-polyfill-corejs3 "^0.8.1" + babel-plugin-polyfill-regenerator "^0.5.0" + core-js-compat "^3.30.2" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@^7.8.4": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb" + integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.21.9": + version "7.21.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.21.9.tgz#bf8dad2859130ae46088a99c1f265394877446fb" + integrity sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ== + dependencies: + "@babel/code-frame" "^7.21.4" + "@babel/parser" "^7.21.9" + "@babel/types" "^7.21.5" + +"@babel/traverse@^7.20.5", "@babel/traverse@^7.22.1": + version "7.22.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.4.tgz#c3cf96c5c290bd13b55e29d025274057727664c0" + integrity sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ== + dependencies: + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.22.3" + "@babel/helper-environment-visitor" "^7.22.1" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.22.4" + "@babel/types" "^7.22.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.5", "@babel/types@^7.21.0", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.22.0", "@babel/types@^7.22.3", "@babel/types@^7.22.4", "@babel/types@^7.4.4": + version "7.22.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.4.tgz#56a2653ae7e7591365dabf20b76295410684c071" + integrity sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA== + dependencies: + "@babel/helper-string-parser" "^7.21.5" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" + integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.40.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.40.0.tgz#ae73dc9ec5237f2794c4f79efd6a4c73b13daf23" + integrity sha512-nbq2mvc/tBrK9zQQuItvjJl++GTN5j06DaPtp3hZCpngmG6Q3xoyEmd0TwZI0gAy/G1X0zhGBbr2imsGFdFV0g== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/node@*": + version "20.2.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb" + integrity sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ== + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== + +"@webpack-cli/info@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== + dependencies: + envinfo "^7.7.3" + +"@webpack-cli/serve@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +babel-loader@^8.2: + version "8.3.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" + integrity sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^2.0.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-polyfill-corejs2@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.3.tgz#75044d90ba5043a5fb559ac98496f62f3eb668fd" + integrity sha512-bM3gHc337Dta490gg+/AseNB9L4YLHxq1nGKZZSHbhXv4aTYU2MD2cjza1Ru4S6975YLTaL1K8uJf6ukJhhmtw== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.4.0" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.1.tgz#39248263c38191f0d226f928d666e6db1b4b3a8a" + integrity sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.0" + core-js-compat "^3.30.1" + +babel-plugin-polyfill-regenerator@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.0.tgz#e7344d88d9ef18a3c47ded99362ae4a757609380" + integrity sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.0" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.14.5, browserslist@^4.21.3, browserslist@^4.21.5: + version "4.21.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.7.tgz#e2b420947e5fb0a58e8f4668ae6e23488127e551" + integrity sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA== + dependencies: + caniuse-lite "^1.0.30001489" + electron-to-chromium "^1.4.411" + node-releases "^2.0.12" + update-browserslist-db "^1.0.11" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +caniuse-lite@^1.0.30001489: + version "1.0.30001495" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz#64a0ccef1911a9dcff647115b4430f8eff1ef2d9" + integrity sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +"chokidar@>=3.0.0 <4.0.0": + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +core-js-compat@^3.30.1, core-js-compat@^3.30.2: + version "3.30.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.30.2.tgz#83f136e375babdb8c80ad3c22d67c69098c1dd8b" + integrity sha512-nriW1nuJjUgvkEjIot1Spwakz52V9YkYHZAQG6A1eCgC8AA1p0zngrQEP9R0+V6hji5XilWKG1Bd0YRppmGimA== + dependencies: + browserslist "^4.21.5" + +core-js@^3.25.0: + version "3.30.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.30.2.tgz#6528abfda65e5ad728143ea23f7a14f0dcf503fc" + integrity sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg== + +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^7.0.1, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +electron-to-chromium@^1.4.411: + version "1.4.425" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.425.tgz#399df13091b836d28283a545c25c8e4d9da86da8" + integrity sha512-wv1NufHxu11zfDbY4fglYQApMswleE9FL/DSeyOyauVXDZ+Kco96JK/tPfBUaDqfRarYp2WH2hJ/5UnVywp9Jg== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +enhanced-resolve@^5.14.1: + version "5.14.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz#de684b6803724477a4af5d74ccae5de52c25f6b3" + integrity sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +envinfo@^7.7.3: + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +es-module-lexer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.2.1.tgz#ba303831f63e6a394983fde2f97ad77b22324527" + integrity sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +immutable@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be" + integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.11.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json5@^2.1.2, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +klona@^2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.12: + version "2.0.12" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039" + integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.1.0, pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== + dependencies: + resolve "^1.9.0" + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-transform@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.14.2, resolve@^1.9.0: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +sass-loader@^12.1.0: + version "12.6.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.6.0.tgz#5148362c8e2cdd4b950f3c63ac5d16dbfed37bcb" + integrity sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA== + dependencies: + klona "^2.0.4" + neo-async "^2.6.2" + +sass@^1.42.1: + version "1.63.2" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.63.2.tgz#75f7d9a8e67d1d5b98a989507f4d98b6067b1f75" + integrity sha512-u56TU0AIFqMtauKl/OJ1AeFsXqRHkgO7nCWmHaDwfxDo9GUMSqBA4NEh6GMuh1CYVM7zuROYtZrHzPc2ixK+ww== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.2.0.tgz#7dff4881064a4f22c09f0c6a1457feb820fd0636" + integrity sha512-0zTyLGyDJYd/MBxG1AhJkKa6fpEBds4OQO2ut0w7OYG+ZGhGea09lijvzsqegYSik88zc7cUtIlnnO+/BvD6gQ== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +"source-map-js@>=0.6.2 <2.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.7: + version "5.3.9" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" + integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.16.8" + +terser@^5.16.8: + version "5.17.7" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.7.tgz#2a8b134826fe179b711969fd9d9a0c2479b2a8c3" + integrity sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-cli@^4.10: + version "4.10.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" + integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" + colorette "^2.0.14" + commander "^7.0.0" + cross-spawn "^7.0.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^2.2.0" + rechoir "^0.7.0" + webpack-merge "^5.7.3" + +webpack-merge@^5.7.3: + version "5.9.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" + integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.76: + version "5.86.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.86.0.tgz#b0eb81794b62aee0b7e7eb8c5073495217d9fc6d" + integrity sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.14.1" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.2" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.7" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/package.json b/package.json index ccc69d50d..83284423b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "install:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn install", "install:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn install", "install:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn install", + "install:modules:ppcp-subscription": "cd modules/ppcp-subscription && yarn install", "install:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn install", "install:modules:ppcp-compat": "cd modules/ppcp-compat && yarn install", "install:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn install", @@ -20,6 +21,7 @@ "build:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run build", "build:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run build", "build:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn run build", + "build:modules:ppcp-subscription": "cd modules/ppcp-subscription && yarn run build", "build:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn run build", "build:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run build", "build:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run build", @@ -29,6 +31,7 @@ "watch:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run watch", "watch:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run watch", "watch:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn run watch", + "watch:modules:ppcp-subscription": "cd modules/ppcp-subscription && yarn run watch", "watch:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn run watch", "watch:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run watch", "watch:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run watch", From 40b00d7fb0a937625df6fb9500a366173fb7c077 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 8 Jun 2023 16:49:17 +0200 Subject: [PATCH 04/32] Display PayPal button only if cart contains only one subscription product --- .../src/Helper/SubscriptionHelper.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index 8b3034acd..2250296b2 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -180,6 +180,7 @@ class SubscriptionHelper { if ( $subscription_mode !== 'subscriptions_api' || ! $this->paypal_subscription_id() + || ! $this->cart_contains_only_one_item() ) { return false; } @@ -218,4 +219,25 @@ class SubscriptionHelper { return ''; } + + /** + * Checks if cart contains only one item. + * + * @return bool + */ + public function cart_contains_only_one_item(): bool { + if ( ! $this->plugin_is_active() ) { + return false; + } + $cart = WC()->cart; + if ( ! $cart || $cart->is_empty() ) { + return false; + } + + if ( count( $cart->get_cart() ) > 1 ) { + return false; + } + + return true; + } } From d83d26c5f5405c6106581043792ac74a5f276350 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 12 Jun 2023 15:14:26 +0200 Subject: [PATCH 05/32] Remove subscriptions schedule metabox and add custom one --- .../src/FreeTrialHandlerTrait.php | 2 - .../src/SubscriptionModule.php | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php b/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php index 8e309f4ce..cbc6e02db 100644 --- a/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php +++ b/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php @@ -10,8 +10,6 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Subscription; use WC_Order; -use WC_Product; -use WC_Subscription; use WC_Subscriptions_Product; use WC_Subscriptions_Synchroniser; diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 00ae5b516..0686e602f 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -28,6 +28,7 @@ use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; +use WP_Post; /** * Class SubscriptionModule @@ -165,6 +166,7 @@ class SubscriptionModule implements ModuleInterface { return; } + //phpcs:disable WordPress.Security.NonceVerification.Recommended $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); $product = wc_get_product( $post_id ); if ( ! is_a( $product, WC_Product::class ) ) { @@ -194,6 +196,45 @@ class SubscriptionModule implements ModuleInterface { ); } ); + + add_action( + 'add_meta_boxes', + function( string $post_type, WP_Post $post ) use ( $c ) { + if ( $post_type !== 'shop_subscription' ) { + return; + } + + $subscription = wcs_get_subscription( $post->ID ); + if ( ! is_a( $subscription, WC_Subscription::class ) ) { + return; + } + + $subscription_id = $subscription->get_meta( 'ppcp_subscription' ) ?? ''; + if ( ! $subscription_id ) { + return; + } + + $screen_id = wc_get_page_screen_id( 'shop_subscription' ); + remove_meta_box( 'woocommerce-subscription-schedule', $screen_id, 'side' ); + + $environment = $c->get( 'onboarding.environment' ); + add_meta_box( + 'ppcp_paypal_subscription', + __( 'PayPal Subscription', 'woocommerce-paypal-payments' ), + function() use ( $subscription_id, $environment ) { + $host = $environment->current_environment_is( Environment::SANDBOX ) ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com'; + $url = trailingslashit( $host ) . 'billing/subscriptions/' . $subscription_id; + echo '

' . esc_html__( 'This subscription is linked to a PayPal Subscription, Cancel it to unlink.', 'woocommerce-paypal-payments' ) . '

'; + echo '

' . esc_html__( 'Subscription:', 'woocommerce-paypal-payments' ) . ' ' . esc_attr( $subscription_id ) . '

'; + }, + $post_type, + 'side' + ); + + }, + 30, + 2 + ); } /** From f9ed01e5c4af653c3cef3c9ec5a612cc2cc42801 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 13 Jun 2023 11:33:24 +0200 Subject: [PATCH 06/32] Fix single product button render conditional --- .../ContextBootstrap/SingleProductBootstap.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 2237eb2b1..1d14fc7e0 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -60,7 +60,7 @@ class SingleProductBootstap { return document.querySelector('form.cart') !== null && !this.priceAmountIsZero() && !this.isSubscriptionMode() - && PayPalCommerceGateway.subscription_plan_id !== ''; + && this.subscriptionHasPlan(); } priceAmount() { @@ -100,6 +100,18 @@ class SingleProductBootstap { || document.querySelector('.wcsatt-options-prompt-label-subscription input[type="radio"]:checked') !== null; // grouped } + subscriptionHasPlan() { + if (PayPalCommerceGateway.data_client_id.has_subscriptions) { + if (PayPalCommerceGateway.subscription_plan_id !== '') { + return true; + } + + return false; + } + + return true; + } + render() { const actionHandler = new SingleProductActionHandler( this.gateway, From 87325585f1c58c954de8b76d7311953c168a17e6 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 13 Jun 2023 11:46:56 +0200 Subject: [PATCH 07/32] Fix cart button render conditional --- .../js/modules/ContextBootstrap/CartBootstap.js | 3 ++- .../ContextBootstrap/SingleProductBootstap.js | 15 ++------------- .../resources/js/modules/Helper/Subscriptions.js | 12 ++++++++++++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index 72d28932b..b22010203 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -1,5 +1,6 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; import {setVisible} from "../Helper/Hiding"; +import {subscriptionHasPlan} from "../Helper/Subscriptions"; class CartBootstrap { constructor(gateway, renderer, errorHandler) { @@ -41,7 +42,7 @@ class CartBootstrap { } shouldRender() { - return document.querySelector(this.gateway.button.wrapper) !== null; + return document.querySelector(this.gateway.button.wrapper) !== null && subscriptionHasPlan(); } render() { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 1d14fc7e0..5c625b54e 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -2,6 +2,7 @@ import UpdateCart from "../Helper/UpdateCart"; import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler"; import {hide, show, setVisible} from "../Helper/Hiding"; import ButtonsToggleListener from "../Helper/ButtonsToggleListener"; +import {subscriptionHasPlan} from "../Helper/Subscriptions"; class SingleProductBootstap { constructor(gateway, renderer, messages, errorHandler) { @@ -60,7 +61,7 @@ class SingleProductBootstap { return document.querySelector('form.cart') !== null && !this.priceAmountIsZero() && !this.isSubscriptionMode() - && this.subscriptionHasPlan(); + && subscriptionHasPlan(); } priceAmount() { @@ -100,18 +101,6 @@ class SingleProductBootstap { || document.querySelector('.wcsatt-options-prompt-label-subscription input[type="radio"]:checked') !== null; // grouped } - subscriptionHasPlan() { - if (PayPalCommerceGateway.data_client_id.has_subscriptions) { - if (PayPalCommerceGateway.subscription_plan_id !== '') { - return true; - } - - return false; - } - - return true; - } - render() { const actionHandler = new SingleProductActionHandler( this.gateway, diff --git a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js index a205ac459..4fd4ae383 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js +++ b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js @@ -2,3 +2,15 @@ export const isChangePaymentPage = () => { const urlParams = new URLSearchParams(window.location.search) return urlParams.has('change_payment_method'); } + +export const subscriptionHasPlan = () => { + if (PayPalCommerceGateway.data_client_id.has_subscriptions) { + if (PayPalCommerceGateway.subscription_plan_id !== '') { + return true; + } + + return false; + } + + return true; +} From 7f25e1edd99d145a6bd14257e0b7e3cbf793908b Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 13 Jun 2023 12:17:49 +0200 Subject: [PATCH 08/32] Update subscription mode description --- modules/ppcp-wc-gateway/services.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 9025bf9e1..74f6285b2 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -781,7 +781,14 @@ return array( ), 'paypal_saved_payments' => array( 'heading' => __( 'Saved payments', 'woocommerce-paypal-payments' ), - 'description' => __( 'PayPal can save your customers’ payment methods.', 'woocommerce-paypal-payments' ), + 'description' => sprintf( + // translators: %1$s, %2$s, %3$s and %4$s are a link tags. + __( 'PayPal can securely store your customers\' payment methods for %1$sfuture payments%2$s and %3$ssubscriptions%4$s, simplifying the checkout process and enabling recurring transactions on your website.', 'woocommerce-paypal-payments' ), + '', + '', + '', + '' + ), 'type' => 'ppcp-heading', 'screens' => array( State::STATE_START, From d9ba42e45b802298ca32deb375f6eb7518c9b3b7 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 14 Jun 2023 12:37:59 +0200 Subject: [PATCH 09/32] Add tooltip for connect PayPal checkbox --- modules/ppcp-subscription/src/SubscriptionModule.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 0686e602f..035876380 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -708,7 +708,9 @@ class SubscriptionModule implements ModuleInterface { $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); echo ''; } From 8c407546a3fc6e51f731b623c3a389fe9224d0b2 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 15 Jun 2023 15:59:16 +0200 Subject: [PATCH 11/32] Add spinner to unlink plan button --- .../resources/js/paypal-subscription.js | 28 +++++++++++++++++-- .../src/DeactivatePlanEndpoint.php | 2 +- .../src/SubscriptionModule.php | 7 +++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index 9207e2f28..bcf41a527 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -18,8 +18,13 @@ document.addEventListener( subscriptionTrialPeriod.setAttribute('disabled', 'disabled'); } - document.getElementById('ppcp_unlink_sub_plan').addEventListener('click', (event)=>{ + const unlinkBtn = document.getElementById('ppcp_unlink_sub_plan'); + unlinkBtn.addEventListener('click', (event)=>{ event.preventDefault(); + unlinkBtn.disabled = true; + const spinner = document.getElementById('spinner-unlink-plan'); + spinner.style.display = 'inline-block'; + fetch(PayPalCommerceGatewayPayPalSubscription.ajax.deactivate_plan.endpoint, { method: 'POST', headers: { @@ -34,7 +39,26 @@ document.addEventListener( }).then(function (res) { return res.json(); }).then(function (data) { - console.log(data) + if (!data.success) { + unlinkBtn.disabled = false; + spinner.style.display = 'none'; + console.error(data); + throw Error(data.data.message); + } + + const enableSubscription = document.getElementById('ppcp-enable-subscription'); + const product = document.getElementById('pcpp-product'); + const plan = document.getElementById('pcpp-plan'); + enableSubscription.style.display = 'none'; + product.style.display = 'none'; + plan.style.display = 'none'; + + const enable_subscription_product = document.getElementById('ppcp_enable_subscription_product'); + enable_subscription_product.disabled = true; + + const planUnlinked = document.getElementById('pcpp-plan-unlinked'); + planUnlinked.style.display = 'block'; + }); }); }); diff --git a/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php b/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php index 14c5b5cbc..c2d490e81 100644 --- a/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php +++ b/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php @@ -70,9 +70,9 @@ class DeactivatePlanEndpoint { $product = wc_get_product( $product_id ); if ( WC_Subscriptions_Product::is_subscription( $product ) ) { $product->delete_meta_data( '_ppcp_enable_subscription_product' ); + $product->delete_meta_data( '_ppcp_subscription_plan_name' ); $product->delete_meta_data( 'ppcp_subscription_product' ); $product->delete_meta_data( 'ppcp_subscription_plan' ); - $product->delete_meta_data( 'ppcp_subscription_plan_name' ); $product->save(); } } diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 65ece0859..9d690129a 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -729,12 +729,13 @@ class SubscriptionModule implements ModuleInterface { $subscription_plan = $product->get_meta( 'ppcp_subscription_plan' ); if ( $subscription_product && $subscription_plan ) { if ( $enable_subscription_product !== 'yes' ) { - echo '

' . esc_html__( 'Unlink PayPal Subscription Plan', 'woocommerce-paypal-payments' ) . '

'; + echo '

'; + echo ''; } $environment = $c->get( 'onboarding.environment' ); $host = $environment->current_environment_is( Environment::SANDBOX ) ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com'; - echo '

' . esc_attr( $subscription_product['id'] ) . '

'; - echo '

' . esc_attr( $subscription_plan['id'] ) . '

'; + echo '

' . esc_attr( $subscription_product['id'] ) . '

'; + echo '

' . esc_attr( $subscription_plan['id'] ) . '

'; } else { echo '

'; } From 09c7537e48f14114d6d78397a0a070dfedc5cae4 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Fri, 16 Jun 2023 16:11:45 +0200 Subject: [PATCH 12/32] Hide non updatable form fields if subscription product connected to PayPal --- .../ContextBootstrap/SingleProductBootstap.js | 3 +++ .../resources/js/paypal-subscription.js | 16 ++++++++-------- .../src/FreeTrialHandlerTrait.php | 5 ++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 5c625b54e..7ee40db54 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -91,6 +91,9 @@ class SingleProductBootstap { } priceAmountIsZero() { + if(subscriptionHasPlan()) { + return false; + } const price = this.priceAmount(); return !price || price === 0; } diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index bcf41a527..c42ca2597 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -8,18 +8,15 @@ document.addEventListener( const subscriptionPeriod = document.querySelector('#_subscription_period'); subscriptionPeriod.setAttribute('disabled', 'disabled'); - const subscriptionLength = document.querySelector('#_subscription_length'); - subscriptionLength.setAttribute('disabled', 'disabled'); + const subscriptionLength = document.querySelector('._subscription_length_field'); + subscriptionLength.style.display = 'none'; - const subscriptionTrialLength = document.querySelector('#_subscription_trial_length'); - subscriptionTrialLength.setAttribute('disabled', 'disabled'); - - const subscriptionTrialPeriod = document.querySelector('#_subscription_trial_period'); - subscriptionTrialPeriod.setAttribute('disabled', 'disabled'); + const subscriptionTrial = document.querySelector('._subscription_trial_length_field'); + subscriptionTrial.style.display = 'none'; } const unlinkBtn = document.getElementById('ppcp_unlink_sub_plan'); - unlinkBtn.addEventListener('click', (event)=>{ + unlinkBtn?.addEventListener('click', (event)=>{ event.preventDefault(); unlinkBtn.disabled = true; const spinner = document.getElementById('spinner-unlink-plan'); @@ -59,6 +56,9 @@ document.addEventListener( const planUnlinked = document.getElementById('pcpp-plan-unlinked'); planUnlinked.style.display = 'block'; + setTimeout(() => { + location.reload(); + }, 1000) }); }); }); diff --git a/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php b/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php index cbc6e02db..d528ff554 100644 --- a/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php +++ b/modules/ppcp-subscription/src/FreeTrialHandlerTrait.php @@ -56,7 +56,10 @@ trait FreeTrialHandlerTrait { $product = wc_get_product(); - if ( ! $product || ! WC_Subscriptions_Product::is_subscription( $product ) ) { + if ( + ! $product || ! WC_Subscriptions_Product::is_subscription( $product ) + || $product->get_meta( '_ppcp_enable_subscription_product' ) === 'yes' + ) { return false; } From 157dd41b7cddcc811db01fe03a77119f1b72fd23 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Fri, 16 Jun 2023 16:28:15 +0200 Subject: [PATCH 13/32] Fix psalm --- .psalm/wcs.php | 9 +++++++++ .../ppcp-subscription/src/DeactivatePlanEndpoint.php | 3 ++- modules/ppcp-subscription/src/SubscriptionModule.php | 10 +++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.psalm/wcs.php b/.psalm/wcs.php index 873fd4d50..a35088c88 100644 --- a/.psalm/wcs.php +++ b/.psalm/wcs.php @@ -2084,3 +2084,12 @@ function wcs_find_matching_line_item($order, $subscription_item, $match_type = ' function wcs_order_contains_product($order, $product) { } + +/** + * Get page ID for a specific WC resource. + * + * @param string $for Name of the resource. + * + * @return string Page ID. Empty string if resource not found. + */ +function wc_get_page_screen_id( $for ) {} diff --git a/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php b/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php index c2d490e81..fe10c0638 100644 --- a/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php +++ b/modules/ppcp-subscription/src/DeactivatePlanEndpoint.php @@ -10,6 +10,7 @@ declare( strict_types=1 ); namespace WooCommerce\PayPalCommerce\Subscription; use Exception; +use WC_Product; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingPlans; use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData; @@ -68,7 +69,7 @@ class DeactivatePlanEndpoint { $product_id = $data['product_id'] ?? ''; if ( $product_id ) { $product = wc_get_product( $product_id ); - if ( WC_Subscriptions_Product::is_subscription( $product ) ) { + if ( is_a( $product, WC_Product::class ) && WC_Subscriptions_Product::is_subscription( $product ) ) { $product->delete_meta_data( '_ppcp_enable_subscription_product' ); $product->delete_meta_data( '_ppcp_subscription_plan_name' ); $product->delete_meta_data( 'ppcp_subscription_product' ); diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 9d690129a..7c6d71a7c 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -160,7 +160,15 @@ class SubscriptionModule implements ModuleInterface { add_action( 'admin_enqueue_scripts', + /** + * Param types removed to avoid third-party issues. + * + * @psalm-suppress MissingClosureParamType + */ function( $hook ) use ( $c ) { + if ( ! is_string( $hook ) ) { + return; + } $settings = $c->get( 'wcgateway.settings' ); $subscription_mode = $settings->has( 'subscriptions_mode' ) ? $settings->get( 'subscriptions_mode' ) : ''; if ( $hook !== 'post.php' || $subscription_mode !== 'subscriptions_api' ) { @@ -183,7 +191,7 @@ class SubscriptionModule implements ModuleInterface { true ); - $plan = $product->get_meta( 'ppcp_subscription_plan' ) ?? null; + $plan = $product->get_meta( 'ppcp_subscription_plan' ) ?? array(); $plan_id = $plan['id'] ?? ''; wp_localize_script( 'ppcp-paypal-subscription', From 06bfe33db260098cf46d788e02663120a3c5ba42 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 21 Jun 2023 15:42:18 +0200 Subject: [PATCH 14/32] Working on subscriptions (WIP) --- .../js/modules/Helper/Subscriptions.js | 2 +- .../resources/js/paypal-subscription.js | 2 + .../src/Helper/SubscriptionHelper.php | 4 +- .../src/SubscriptionModule.php | 213 +++++++++++++----- .../src/Checkout/DisableGateways.php | 3 +- 5 files changed, 165 insertions(+), 59 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js index 4fd4ae383..bac46fbad 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js +++ b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js @@ -4,7 +4,7 @@ export const isChangePaymentPage = () => { } export const subscriptionHasPlan = () => { - if (PayPalCommerceGateway.data_client_id.has_subscriptions) { + if (PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled && PayPalCommerceGateway.data_client_id.has_subscriptions) { if (PayPalCommerceGateway.subscription_plan_id !== '') { return true; } diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index c42ca2597..ae71a1b8e 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -15,6 +15,8 @@ document.addEventListener( subscriptionTrial.style.display = 'none'; } + console.log('testing') + const unlinkBtn = document.getElementById('ppcp_unlink_sub_plan'); unlinkBtn?.addEventListener('click', (event)=>{ event.preventDefault(); diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index 2250296b2..6bd1e40fe 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -176,10 +176,8 @@ class SubscriptionHelper { * @throws NotFoundException If setting is not found. */ public function checkout_subscription_product_allowed(): bool { - $subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : ''; if ( - $subscription_mode !== 'subscriptions_api' - || ! $this->paypal_subscription_id() + ! $this->paypal_subscription_id() || ! $this->cart_contains_only_one_item() ) { return false; diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 7c6d71a7c..c9ba156fc 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Subscription; use Exception; use WC_Product; +use WC_Product_Subscription_Variation; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; @@ -178,7 +179,7 @@ class SubscriptionModule implements ModuleInterface { //phpcs:disable WordPress.Security.NonceVerification.Recommended $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); $product = wc_get_product( $post_id ); - if ( ! is_a( $product, WC_Product::class ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { + if ( ! ( is_a( $product, WC_Product::class) || is_a( $product, WC_Product_Subscription_Variation::class) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { return; } @@ -463,40 +464,28 @@ class SubscriptionModule implements ModuleInterface { return; } - $enable_subscription_product = wc_clean( wp_unslash( $_POST['_ppcp_enable_subscription_product'] ?? '' ) ); - $product->update_meta_data( '_ppcp_enable_subscription_product', $enable_subscription_product ); - $product->save(); - - if ( $product->get_type() === 'subscription' && $enable_subscription_product === 'yes' ) { - $subscriptions_api_handler = $c->get( 'subscription.api-handler' ); - assert( $subscriptions_api_handler instanceof SubscriptionsApiHandler ); - - if ( $product->meta_exists( 'ppcp_subscription_product' ) && $product->meta_exists( 'ppcp_subscription_plan' ) ) { - $subscriptions_api_handler->update_product( $product ); - $subscriptions_api_handler->update_plan( $product ); - return; - } - - if ( ! $product->meta_exists( 'ppcp_subscription_product' ) ) { - $subscriptions_api_handler->create_product( $product ); - } - - if ( $product->meta_exists( 'ppcp_subscription_product' ) && ! $product->meta_exists( 'ppcp_subscription_plan' ) ) { - $subscription_plan_name = wc_clean( wp_unslash( $_POST['_ppcp_subscription_plan_name'] ?? '' ) ); - if ( ! is_string( $subscription_plan_name ) ) { - return; - } - - $product->update_meta_data( '_ppcp_subscription_plan_name', $subscription_plan_name ); - $product->save(); - - $subscriptions_api_handler->create_plan( $subscription_plan_name, $product ); - } - } + $subscriptions_api_handler = $c->get('subscription.api-handler'); + assert($subscriptions_api_handler instanceof SubscriptionsApiHandler); + $this->update_subscription_product_meta($product, $subscriptions_api_handler); }, 12 ); + add_action('woocommerce_save_product_variation', function($variation_id) use($c){ + if ( ! WC_Subscriptions_Product::is_subscription( $variation_id ) || empty( $_POST['_wcsnonce_save_variations'] ) || ! wp_verify_nonce( $_POST['_wcsnonce_save_variations'], 'wcs_subscription_variations' ) ) { + return; + } + + $product = wc_get_product( $variation_id ); + if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) { + return; + } + + $subscriptions_api_handler = $c->get('subscription.api-handler'); + assert($subscriptions_api_handler instanceof SubscriptionsApiHandler); + $this->update_subscription_product_meta($product, $subscriptions_api_handler); + }); + add_action( 'woocommerce_process_shop_subscription_meta', /** @@ -705,6 +694,32 @@ class SubscriptionModule implements ModuleInterface { } ); + add_action( + 'woocommerce_variation_options_pricing', + function( $loop, $variation_data, $variation ) use ( $c ) { + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + try { + $subscriptions_mode = $settings->get( 'subscriptions_mode' ); + if ( $subscriptions_mode === 'subscriptions_api' ) { + $product = wc_get_product( $variation->ID ); + if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) { + return; + } + + $environment = $c->get( 'onboarding.environment' ); + $this->render_paypal_subscription_fields( $product, $environment ); + + } + } catch ( NotFoundException $exception ) { + return; + } + }, + 10, + 3 + ); + add_action( 'woocommerce_product_options_general_product_data', function() use ( $c ) { @@ -725,29 +740,8 @@ class SubscriptionModule implements ModuleInterface { return; } - $enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' ); - $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); - - echo ''; + $environment = $c->get( 'onboarding.environment' ); + $this->render_paypal_subscription_fields( $product, $environment ); } } catch ( NotFoundException $exception ) { return; @@ -832,4 +826,115 @@ class SubscriptionModule implements ModuleInterface { } ); } + + /** + * Render PayPal Subscriptions fields. + * + * @param WC_Product $product WC Product. + * @param Environment $environment The environment. + * @return void + */ + private function render_paypal_subscription_fields( WC_Product $product, Environment $environment ): void { + $enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' ); + $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); + + //echo ''; + } + + /** + * Updates subscription product meta. + * + * @param WC_Product $product + * @param SubscriptionsApiHandler $subscriptions_api_handler + * @return void + */ + private function update_subscription_product_meta(WC_Product $product, SubscriptionsApiHandler $subscriptions_api_handler): void + { + $enable_subscription_product = wc_clean(wp_unslash($_POST['_ppcp_enable_subscription_product'] ?? '')); + $product->update_meta_data('_ppcp_enable_subscription_product', $enable_subscription_product); + $product->save(); + + if (($product->get_type() === 'subscription' || $product->get_type() === 'subscription_variation') && $enable_subscription_product === 'yes') { + if ($product->meta_exists('ppcp_subscription_product') && $product->meta_exists('ppcp_subscription_plan')) { + $subscriptions_api_handler->update_product($product); + $subscriptions_api_handler->update_plan($product); + return; + } + + if (!$product->meta_exists('ppcp_subscription_product')) { + $subscriptions_api_handler->create_product($product); + } + + if ($product->meta_exists('ppcp_subscription_product') && !$product->meta_exists('ppcp_subscription_plan')) { + $subscription_plan_name = wc_clean(wp_unslash($_POST['_ppcp_subscription_plan_name'] ?? '')); + if (!is_string($subscription_plan_name)) { + return; + } + + $product->update_meta_data('_ppcp_subscription_plan_name', $subscription_plan_name); + $product->save(); + + $subscriptions_api_handler->create_plan($subscription_plan_name, $product); + } + } + } } diff --git a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php index e5078ae3f..d2f07d7f1 100644 --- a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php +++ b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php @@ -124,8 +124,9 @@ class DisableGateways { return true; } + $subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : ''; if ( - is_checkout() + (is_checkout() && $subscription_mode === 'subscriptions_api') && $this->subscription_helper->cart_contains_subscription() && ! $this->subscription_helper->checkout_subscription_product_allowed() ) { From c8e40b56c473b49e46fca840af42e9081dbcd581 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 28 Jun 2023 17:17:22 +0200 Subject: [PATCH 15/32] Add support for variable subscriptions (WIP) --- .../SingleProductActionHandler.js | 23 ++++++++++++-- .../ContextBootstrap/SingleProductBootstap.js | 21 ++++++++++++- .../js/modules/Helper/Subscriptions.js | 1 + .../ppcp-button/src/Assets/SmartButton.php | 1 + .../src/Helper/SubscriptionHelper.php | 31 +++++++++++++++++++ .../src/SubscriptionsApiHandler.php | 2 +- 6 files changed, 75 insertions(+), 4 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js index 3c3371542..152ba64f0 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js @@ -18,11 +18,30 @@ class SingleProductActionHandler { this.errorHandler = errorHandler; } - subscriptionsConfiguration() { + getPlanIdFromVariation = (variation) => { + let subscription_plan = ''; + PayPalCommerceGateway.variable_paypal_subscription_variations.forEach((element) => { + let obj = {}; + variation.forEach(({name, value}) => { + Object.assign(obj, {[name.replace('attribute_', '')]: value}); + }) + + if(JSON.stringify(obj) === JSON.stringify(element.attributes) && element.subscription_plan !== '') { + subscription_plan = element.subscription_plan; + } + }); + + return subscription_plan; + } + + subscriptionsConfiguration(selected_variation = null) { + const subscription_plan = selected_variation !== null ? this.getPlanIdFromVariation(selected_variation) : this.config.subscription_plan_id + console.log(subscription_plan) + return { createSubscription: (data, actions) => { return actions.subscription.create({ - 'plan_id': this.config.subscription_plan_id + 'plan_id': subscription_plan }); }, onApprove: (data, actions) => { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 7ee40db54..25b71b1ab 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -13,6 +13,25 @@ class SingleProductBootstap { this.mutationObserver = new MutationObserver(this.handleChange.bind(this)); } + variations() { + if (!this.hasVariations()) { + return null; + } + + const attributes = [...document.querySelector('form.cart')?.querySelectorAll("[name^='attribute_']")].map( + (element) => { + return { + value: element.value, + name: element.name + } + } + ); + return attributes; + } + + hasVariations() { + return document.querySelector('form.cart')?.classList.contains('variations_form'); + } handleChange() { const shouldRender = this.shouldRender(); @@ -119,7 +138,7 @@ class SingleProductBootstap { PayPalCommerceGateway.data_client_id.has_subscriptions && PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled ) { - this.renderer.render(actionHandler.subscriptionsConfiguration()); + this.renderer.render(actionHandler.subscriptionsConfiguration(this.variations())); return; } diff --git a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js index bac46fbad..89ef910fe 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js +++ b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js @@ -4,6 +4,7 @@ export const isChangePaymentPage = () => { } export const subscriptionHasPlan = () => { + return true; if (PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled && PayPalCommerceGateway.data_client_id.has_subscriptions) { if (PayPalCommerceGateway.subscription_plan_id !== '') { return true; diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index ff2472df2..ad0170fb5 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -851,6 +851,7 @@ class SmartButton implements SmartButtonInterface { ), ), 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), + 'variable_paypal_subscription_variations' => $this->subscription_helper->variable_paypal_subscription_variations(), 'enforce_vault' => $this->has_subscriptions(), 'can_save_vault_token' => $this->can_save_vault_token(), 'is_free_trial_cart' => $is_free_trial_cart, diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index 6bd1e40fe..619fbc658 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Subscription\Helper; use WC_Product; +use WC_Product_Subscription_Variation; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; @@ -218,6 +219,36 @@ class SubscriptionHelper { return ''; } + public function variable_paypal_subscription_variations(): array { + $variations = array(); + if ( ! $this->current_product_is_subscription() ) { + return $variations; + } + + $product = wc_get_product(); + assert( $product instanceof WC_Product ); + if ( $product->get_type() !== 'variable-subscription' ) { + return $variations; + } + + $variation_ids = $product->get_children(); + foreach ($variation_ids as $id) { + $product = wc_get_product($id); + if(! is_a($product, WC_Product_Subscription_Variation::class )) { + continue; + } + + $subscription_plan = $product->get_meta('ppcp_subscription_plan') ?? ''; + $variations[] = array( + 'id' => $product->get_id(), + 'attributes' => $product->get_attributes(), + 'subscription_plan' => $subscription_plan['id'] ?? '', + ); + } + + return $variations; + } + /** * Checks if cart contains only one item. * diff --git a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php index bdfa9f9b5..569bbf5a5 100644 --- a/modules/ppcp-subscription/src/SubscriptionsApiHandler.php +++ b/modules/ppcp-subscription/src/SubscriptionsApiHandler.php @@ -265,7 +265,7 @@ class SubscriptionsApiHandler { 'REGULAR', array( 'fixed_price' => array( - 'value' => $product->get_meta( '_subscription_price' ), + 'value' => $product->get_meta( '_subscription_price' ) ?: $product->get_price(), 'currency_code' => $this->currency, ), ), From 59afa81160c9ca74e8d36ffb4409cf058d0cb5e2 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 13 Jul 2023 16:22:57 +0200 Subject: [PATCH 16/32] Introduce paypal-js loading wrapper to be able to reload script --- modules/ppcp-button/package.json | 5 +- .../SingleProductActionHandler.js | 3 +- .../modules/ContextBootstrap/CartBootstap.js | 3 +- .../ContextBootstrap/SingleProductBootstap.js | 22 +++++--- .../js/modules/Helper/ScriptLoading.js | 7 +++ .../js/modules/Helper/Subscriptions.js | 12 ----- .../ppcp-button/src/Assets/SmartButton.php | 52 ++++++++++--------- modules/ppcp-button/yarn.lock | 12 +++++ .../resources/js/paypal-subscription.js | 2 - .../src/Checkout/DisableGateways.php | 9 ---- 10 files changed, 65 insertions(+), 62 deletions(-) diff --git a/modules/ppcp-button/package.json b/modules/ppcp-button/package.json index 61e31d70f..77828e436 100644 --- a/modules/ppcp-button/package.json +++ b/modules/ppcp-button/package.json @@ -11,9 +11,10 @@ "Edge >= 14" ], "dependencies": { + "@paypal/paypal-js": "^6.0.0", "core-js": "^3.25.0", - "formdata-polyfill": "^4.0.10", - "deepmerge": "^4.2.2" + "deepmerge": "^4.2.2", + "formdata-polyfill": "^4.0.10" }, "devDependencies": { "@babel/core": "^7.19", diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js index 123381912..1aa3e47bd 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js @@ -35,7 +35,6 @@ class SingleProductActionHandler { subscriptionsConfiguration(selected_variation = null) { const subscription_plan = selected_variation !== null ? this.getPlanIdFromVariation(selected_variation) : this.config.subscription_plan_id - console.log(subscription_plan) return { createSubscription: (data, actions) => { @@ -56,7 +55,7 @@ class SingleProductActionHandler { return res.json(); }).then(() => { const id = document.querySelector('[name="add-to-cart"]').value; - const products = [new Product(id, 1, null)]; + const products = [new Product(id, 1, [])]; fetch(this.config.ajax.change_cart.endpoint, { method: 'POST', diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index 6e65e9be8..504fc4c42 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -1,7 +1,6 @@ import CartActionHandler from '../ActionHandler/CartActionHandler'; import BootstrapHelper from "../Helper/BootstrapHelper"; import {setVisible} from "../Helper/Hiding"; -import {subscriptionHasPlan} from "../Helper/Subscriptions"; class CartBootstrap { constructor(gateway, renderer, errorHandler) { @@ -53,7 +52,7 @@ class CartBootstrap { } shouldRender() { - return document.querySelector(this.gateway.button.wrapper) !== null && subscriptionHasPlan(); + return document.querySelector(this.gateway.button.wrapper) !== null; } shouldEnable() { diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index b3d3e2359..61f167d31 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -2,7 +2,7 @@ import UpdateCart from "../Helper/UpdateCart"; import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler"; import {hide, show} from "../Helper/Hiding"; import BootstrapHelper from "../Helper/BootstrapHelper"; -import {subscriptionHasPlan} from "../Helper/Subscriptions"; +import {loadPaypalJsScript} from "../Helper/ScriptLoading"; class SingleProductBootstap { constructor(gateway, renderer, messages, errorHandler) { @@ -80,8 +80,7 @@ class SingleProductBootstap { shouldRender() { return this.form() !== null - && !this.isWcsattSubscriptionMode() - && subscriptionHasPlan(); + && !this.isWcsattSubscriptionMode(); } shouldEnable() { @@ -120,10 +119,6 @@ class SingleProductBootstap { } priceAmountIsZero() { - if(subscriptionHasPlan()) { - return false; - } - const price = this.priceAmount(); return !price || price === 0; } @@ -168,7 +163,18 @@ class SingleProductBootstap { PayPalCommerceGateway.data_client_id.has_subscriptions && PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled ) { - this.renderer.render(actionHandler.subscriptionsConfiguration(this.variations())); + const buttonWrapper = document.getElementById('ppc-button-ppcp-gateway'); + buttonWrapper.innerHTML = ''; + loadPaypalJsScript( + { + clientId: PayPalCommerceGateway.client_id, + currency: PayPalCommerceGateway.currency, + intent: 'subscription', + vault: true + }, + actionHandler.subscriptionsConfiguration(this.variations()), + this.gateway.button.wrapper + ); return; } diff --git a/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js b/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js index c5742ab19..5925d6263 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js +++ b/modules/ppcp-button/resources/js/modules/Helper/ScriptLoading.js @@ -1,4 +1,5 @@ import dataClientIdAttributeHandler from "../DataClientIdAttributeHandler"; +import {loadScript} from "@paypal/paypal-js"; export const loadPaypalScript = (config, onLoaded) => { if (typeof paypal !== 'undefined') { @@ -22,3 +23,9 @@ export const loadPaypalScript = (config, onLoaded) => { document.body.appendChild(script); } + +export const loadPaypalJsScript = (options, buttons, container) => { + loadScript(options).then((paypal) => { + paypal.Buttons(buttons).render(container); + }); +} diff --git a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js index bac46fbad..a205ac459 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js +++ b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js @@ -2,15 +2,3 @@ export const isChangePaymentPage = () => { const urlParams = new URLSearchParams(window.location.search) return urlParams.has('change_payment_method'); } - -export const subscriptionHasPlan = () => { - if (PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled && PayPalCommerceGateway.data_client_id.has_subscriptions) { - if (PayPalCommerceGateway.subscription_plan_id !== '') { - return true; - } - - return false; - } - - return true; -} diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index d86798eea..9b7f20acc 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -813,10 +813,12 @@ class SmartButton implements SmartButtonInterface { $this->request_data->enqueue_nonce_fix(); $localize = array( - 'url' => add_query_arg( $url_params, 'https://www.paypal.com/sdk/js' ), - 'url_params' => $url_params, - 'script_attributes' => $this->attributes(), - 'data_client_id' => array( + 'url' => add_query_arg( $url_params, 'https://www.paypal.com/sdk/js' ), + 'url_params' => $url_params, + 'script_attributes' => $this->attributes(), + 'client_id' => $this->client_id, + 'currency' => $this->currency, + 'data_client_id' => array( 'set_attribute' => ( is_checkout() && $this->dcc_is_enabled() ) || $this->can_save_vault_token(), 'endpoint' => \WC_AJAX::get_endpoint( DataClientIdEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( DataClientIdEndpoint::nonce() ), @@ -824,9 +826,9 @@ class SmartButton implements SmartButtonInterface { 'has_subscriptions' => $this->has_subscriptions(), 'paypal_subscriptions_enabled' => $this->paypal_subscriptions_enabled(), ), - 'redirect' => wc_get_checkout_url(), - 'context' => $this->context(), - 'ajax' => array( + 'redirect' => wc_get_checkout_url(), + 'context' => $this->context(), + 'ajax' => array( 'change_cart' => array( 'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ), @@ -859,15 +861,15 @@ class SmartButton implements SmartButtonInterface { 'endpoint' => \WC_AJAX::get_endpoint( CartScriptParamsEndpoint::ENDPOINT ), ), ), - 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), + 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), 'variable_paypal_subscription_variations' => $this->subscription_helper->variable_paypal_subscription_variations(), - 'enforce_vault' => $this->has_subscriptions(), - 'can_save_vault_token' => $this->can_save_vault_token(), - 'is_free_trial_cart' => $is_free_trial_cart, - 'vaulted_paypal_email' => ( is_checkout() && $is_free_trial_cart ) ? $this->get_vaulted_paypal_email() : '', - 'bn_codes' => $this->bn_codes(), - 'payer' => $this->payerData(), - 'button' => array( + 'enforce_vault' => $this->has_subscriptions(), + 'can_save_vault_token' => $this->can_save_vault_token(), + 'is_free_trial_cart' => $is_free_trial_cart, + 'vaulted_paypal_email' => ( is_checkout() && $is_free_trial_cart ) ? $this->get_vaulted_paypal_email() : '', + 'bn_codes' => $this->bn_codes(), + 'payer' => $this->payerData(), + 'button' => array( 'wrapper' => '#ppc-button-' . PayPalGateway::ID, 'is_disabled' => $this->is_button_disabled(), 'mini_cart_wrapper' => '#ppc-button-minicart', @@ -889,7 +891,7 @@ class SmartButton implements SmartButtonInterface { 'tagline' => $this->style_for_context( 'tagline', $this->context() ), ), ), - 'separate_buttons' => array( + 'separate_buttons' => array( 'card' => array( 'id' => CardButtonGateway::ID, 'wrapper' => '#ppc-button-' . CardButtonGateway::ID, @@ -899,7 +901,7 @@ class SmartButton implements SmartButtonInterface { ), ), ), - 'hosted_fields' => array( + 'hosted_fields' => array( 'wrapper' => '#ppcp-hosted-fields', 'labels' => array( 'credit_card_number' => '', @@ -922,8 +924,8 @@ class SmartButton implements SmartButtonInterface { 'valid_cards' => $this->dcc_applies->valid_cards(), 'contingency' => $this->get_3ds_contingency(), ), - 'messages' => $this->message_values(), - 'labels' => array( + 'messages' => $this->message_values(), + 'labels' => array( 'error' => array( 'generic' => __( 'Something went wrong. Please try again or choose another payment source.', @@ -950,12 +952,12 @@ class SmartButton implements SmartButtonInterface { // phpcs:ignore WordPress.WP.I18n 'shipping_field' => _x( 'Shipping %s', 'checkout-validation', 'woocommerce' ), ), - 'order_id' => 'pay-now' === $this->context() ? $this->get_order_pay_id() : 0, - 'single_product_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'product' ), - 'mini_cart_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' ), - 'basic_checkout_validation_enabled' => $this->basic_checkout_validation_enabled, - 'early_checkout_validation_enabled' => $this->early_validation_enabled, - 'funding_sources_without_redirect' => $this->funding_sources_without_redirect, + 'order_id' => 'pay-now' === $this->context() ? $this->get_order_pay_id() : 0, + 'single_product_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'product' ), + 'mini_cart_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' ), + 'basic_checkout_validation_enabled' => $this->basic_checkout_validation_enabled, + 'early_checkout_validation_enabled' => $this->early_validation_enabled, + 'funding_sources_without_redirect' => $this->funding_sources_without_redirect, ); if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) { diff --git a/modules/ppcp-button/yarn.lock b/modules/ppcp-button/yarn.lock index e76c992e1..9d5ebef6e 100644 --- a/modules/ppcp-button/yarn.lock +++ b/modules/ppcp-button/yarn.lock @@ -956,6 +956,13 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@paypal/paypal-js@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@paypal/paypal-js/-/paypal-js-6.0.0.tgz#a5a9556af29e4a0124049bf9a093606f52b8a951" + integrity sha512-FYzjYby9F7tgg4tUxYNseZ6vkeDJcdcjoULsyNhfrWZZjicDpdj5932fZlyUlQXDSR9KlhjXH6H4nPIJ0Lq0Kw== + dependencies: + promise-polyfill "^8.3.0" + "@types/eslint-scope@^3.7.3": version "3.7.4" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" @@ -1858,6 +1865,11 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +promise-polyfill@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63" + integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg== + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index ae71a1b8e..c42ca2597 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -15,8 +15,6 @@ document.addEventListener( subscriptionTrial.style.display = 'none'; } - console.log('testing') - const unlinkBtn = document.getElementById('ppcp_unlink_sub_plan'); unlinkBtn?.addEventListener('click', (event)=>{ event.preventDefault(); diff --git a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php index 380f64818..6afa24f31 100644 --- a/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php +++ b/modules/ppcp-wc-gateway/src/Checkout/DisableGateways.php @@ -129,15 +129,6 @@ class DisableGateways { return true; } - $subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : ''; - if ( - (is_checkout() && $subscription_mode === 'subscriptions_api') - && $this->subscription_helper->cart_contains_subscription() - && ! $this->subscription_helper->checkout_subscription_product_allowed() - ) { - return true; - } - return false; } From 92a59346a77df258b6d0f0b64aabeb3ec7d2943b Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 17 Jul 2023 11:49:51 +0200 Subject: [PATCH 17/32] Add subscription fields for variable subscription (WIP) --- .../src/SubscriptionModule.php | 127 ++++++++++-------- 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index c9ba156fc..d7e39bf7c 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Subscription; use Exception; use WC_Product; use WC_Product_Subscription_Variation; +use WC_Product_Variable_Subscription; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; @@ -694,61 +695,6 @@ class SubscriptionModule implements ModuleInterface { } ); - add_action( - 'woocommerce_variation_options_pricing', - function( $loop, $variation_data, $variation ) use ( $c ) { - $settings = $c->get( 'wcgateway.settings' ); - assert( $settings instanceof Settings ); - - try { - $subscriptions_mode = $settings->get( 'subscriptions_mode' ); - if ( $subscriptions_mode === 'subscriptions_api' ) { - $product = wc_get_product( $variation->ID ); - if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) { - return; - } - - $environment = $c->get( 'onboarding.environment' ); - $this->render_paypal_subscription_fields( $product, $environment ); - - } - } catch ( NotFoundException $exception ) { - return; - } - }, - 10, - 3 - ); - - add_action( - 'woocommerce_product_options_general_product_data', - function() use ( $c ) { - $settings = $c->get( 'wcgateway.settings' ); - assert( $settings instanceof Settings ); - - try { - $subscriptions_mode = $settings->get( 'subscriptions_mode' ); - if ( $subscriptions_mode === 'subscriptions_api' ) { - /** - * Needed for getting global post object. - * - * @psalm-suppress InvalidGlobal - */ - global $post; - $product = wc_get_product( $post->ID ); - if ( ! is_a( $product, WC_Product::class ) ) { - return; - } - - $environment = $c->get( 'onboarding.environment' ); - $this->render_paypal_subscription_fields( $product, $environment ); - } - } catch ( NotFoundException $exception ) { - return; - } - } - ); - add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', /** @@ -825,6 +771,64 @@ class SubscriptionModule implements ModuleInterface { } } ); + + add_action( + 'woocommerce_product_options_general_product_data', + function() use ( $c ) { + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + try { + $subscriptions_mode = $settings->get( 'subscriptions_mode' ); + if ( $subscriptions_mode === 'subscriptions_api' ) { + /** + * Needed for getting global post object. + * + * @psalm-suppress InvalidGlobal + */ + global $post; + $product = wc_get_product( $post->ID ); + if ( ! is_a( $product, WC_Product::class ) ) { + return; + } + + $environment = $c->get( 'onboarding.environment' ); + echo ''; + + } + } catch ( NotFoundException $exception ) { + return; + } + } + ); + + add_action( + 'woocommerce_variation_options_pricing', + function( $loop, $variation_data, $variation ) use ( $c ) { + $settings = $c->get( 'wcgateway.settings' ); + assert( $settings instanceof Settings ); + + try { + $subscriptions_mode = $settings->get( 'subscriptions_mode' ); + if ( $subscriptions_mode === 'subscriptions_api' ) { + $product = wc_get_product( $variation->ID ); + if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) { + return; + } + + $environment = $c->get( 'onboarding.environment' ); + $this->render_paypal_subscription_fields( $product, $environment ); + + } + } catch ( NotFoundException $exception ) { + return; + } + }, + 10, + 3 + ); } /** @@ -835,11 +839,17 @@ class SubscriptionModule implements ModuleInterface { * @return void */ private function render_paypal_subscription_fields( WC_Product $product, Environment $environment ): void { + if(is_a($product, WC_Product_Variable_Subscription::class)) { + $variations = $product->get_available_variations(); + foreach ($variations as $variation) { + $a = 1; + // $variation['variation_id'] + } + } + $enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' ); $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); - //echo ''; } /** From b066fc7ccf752eb15d5a0dac736a492d0073ac57 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 17 Jul 2023 15:13:25 +0200 Subject: [PATCH 18/32] Add subscription support for variable subscriptions --- .../resources/js/paypal-subscription.js | 111 +++++++------- .../src/SubscriptionModule.php | 136 ++++++++++-------- 2 files changed, 137 insertions(+), 110 deletions(-) diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index c42ca2597..a00bf57a0 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -1,64 +1,73 @@ document.addEventListener( 'DOMContentLoaded', () => { - if(PayPalCommerceGatewayPayPalSubscription.product_connected === 'yes') { - const periodInterval = document.querySelector('#_subscription_period_interval'); - periodInterval.setAttribute('disabled', 'disabled'); + const setupProducts = () => { + PayPalCommerceGatewayPayPalSubscriptionProducts?.forEach((product) => { + if(product.product_connected === 'yes') { + const periodInterval = document.querySelector('#_subscription_period_interval'); + periodInterval.setAttribute('disabled', 'disabled'); - const subscriptionPeriod = document.querySelector('#_subscription_period'); - subscriptionPeriod.setAttribute('disabled', 'disabled'); + const subscriptionPeriod = document.querySelector('#_subscription_period'); + subscriptionPeriod.setAttribute('disabled', 'disabled'); - const subscriptionLength = document.querySelector('._subscription_length_field'); - subscriptionLength.style.display = 'none'; + const subscriptionLength = document.querySelector('._subscription_length_field'); + subscriptionLength.style.display = 'none'; - const subscriptionTrial = document.querySelector('._subscription_trial_length_field'); - subscriptionTrial.style.display = 'none'; - } - - const unlinkBtn = document.getElementById('ppcp_unlink_sub_plan'); - unlinkBtn?.addEventListener('click', (event)=>{ - event.preventDefault(); - unlinkBtn.disabled = true; - const spinner = document.getElementById('spinner-unlink-plan'); - spinner.style.display = 'inline-block'; - - fetch(PayPalCommerceGatewayPayPalSubscription.ajax.deactivate_plan.endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - credentials: 'same-origin', - body: JSON.stringify({ - nonce: PayPalCommerceGatewayPayPalSubscription.ajax.deactivate_plan.nonce, - plan_id: PayPalCommerceGatewayPayPalSubscription.ajax.deactivate_plan.plan_id, - product_id: PayPalCommerceGatewayPayPalSubscription.ajax.deactivate_plan.product_id - }) - }).then(function (res) { - return res.json(); - }).then(function (data) { - if (!data.success) { - unlinkBtn.disabled = false; - spinner.style.display = 'none'; - console.error(data); - throw Error(data.data.message); + const subscriptionTrial = document.querySelector('._subscription_trial_length_field'); + subscriptionTrial.style.display = 'none'; } - const enableSubscription = document.getElementById('ppcp-enable-subscription'); - const product = document.getElementById('pcpp-product'); - const plan = document.getElementById('pcpp-plan'); - enableSubscription.style.display = 'none'; - product.style.display = 'none'; - plan.style.display = 'none'; + const unlinkBtn = document.getElementById(`ppcp-unlink-sub-plan-${product.ajax.deactivate_plan.product_id}`); + unlinkBtn?.addEventListener('click', (event)=>{ + event.preventDefault(); + unlinkBtn.disabled = true; + const spinner = document.getElementById('spinner-unlink-plan'); + spinner.style.display = 'inline-block'; - const enable_subscription_product = document.getElementById('ppcp_enable_subscription_product'); - enable_subscription_product.disabled = true; + fetch(product.ajax.deactivate_plan.endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + credentials: 'same-origin', + body: JSON.stringify({ + nonce: product.ajax.deactivate_plan.nonce, + plan_id: product.ajax.deactivate_plan.plan_id, + product_id: product.ajax.deactivate_plan.product_id + }) + }).then(function (res) { + return res.json(); + }).then(function (data) { + if (!data.success) { + unlinkBtn.disabled = false; + spinner.style.display = 'none'; + console.error(data); + throw Error(data.data.message); + } - const planUnlinked = document.getElementById('pcpp-plan-unlinked'); - planUnlinked.style.display = 'block'; + const enableSubscription = document.getElementById('ppcp-enable-subscription'); + const product = document.getElementById('pcpp-product'); + const plan = document.getElementById('pcpp-plan'); + enableSubscription.style.display = 'none'; + product.style.display = 'none'; + plan.style.display = 'none'; - setTimeout(() => { - location.reload(); - }, 1000) - }); + const enable_subscription_product = document.getElementById('ppcp_enable_subscription_product'); + enable_subscription_product.disabled = true; + + const planUnlinked = document.getElementById('pcpp-plan-unlinked'); + planUnlinked.style.display = 'block'; + + setTimeout(() => { + location.reload(); + }, 1000) + }); + }); + }) + } + + setupProducts(); + jQuery( '#woocommerce-product-data' ).on('woocommerce_variations_loaded', () => { + setupProducts(); }); }); diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index d7e39bf7c..5b2978e35 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -180,7 +180,7 @@ class SubscriptionModule implements ModuleInterface { //phpcs:disable WordPress.Security.NonceVerification.Recommended $post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) ); $product = wc_get_product( $post_id ); - if ( ! ( is_a( $product, WC_Product::class) || is_a( $product, WC_Product_Subscription_Variation::class) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { + if ( ! ( is_a( $product, WC_Product::class ) || is_a( $product, WC_Product_Subscription_Variation::class ) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) { return; } @@ -193,22 +193,20 @@ class SubscriptionModule implements ModuleInterface { true ); - $plan = $product->get_meta( 'ppcp_subscription_plan' ) ?? array(); - $plan_id = $plan['id'] ?? ''; + $products = array( $this->set_product_config( $product ) ); + if ( $product->get_type() === 'variable-subscription' ) { + $products = array(); + $available_variations = $product->get_available_variations(); + foreach ( $available_variations as $variation ) { + $variation = wc_get_product_object( 'variation', $variation['variation_id'] ); + $products[] = $this->set_product_config( $variation ); + } + } + wp_localize_script( 'ppcp-paypal-subscription', - 'PayPalCommerceGatewayPayPalSubscription', - array( - 'product_connected' => $product->get_meta( '_ppcp_enable_subscription_product' ) ?? '', - 'ajax' => array( - 'deactivate_plan' => array( - 'endpoint' => \WC_AJAX::get_endpoint( DeactivatePlanEndpoint::ENDPOINT ), - 'nonce' => wp_create_nonce( DeactivatePlanEndpoint::ENDPOINT ), - 'plan_id' => $plan_id, - 'product_id' => $product->get_id(), - ), - ), - ) + 'PayPalCommerceGatewayPayPalSubscriptionProducts', + $products ); } ); @@ -465,27 +463,31 @@ class SubscriptionModule implements ModuleInterface { return; } - $subscriptions_api_handler = $c->get('subscription.api-handler'); - assert($subscriptions_api_handler instanceof SubscriptionsApiHandler); - $this->update_subscription_product_meta($product, $subscriptions_api_handler); + $subscriptions_api_handler = $c->get( 'subscription.api-handler' ); + assert( $subscriptions_api_handler instanceof SubscriptionsApiHandler ); + $this->update_subscription_product_meta( $product, $subscriptions_api_handler ); }, 12 ); - add_action('woocommerce_save_product_variation', function($variation_id) use($c){ - if ( ! WC_Subscriptions_Product::is_subscription( $variation_id ) || empty( $_POST['_wcsnonce_save_variations'] ) || ! wp_verify_nonce( $_POST['_wcsnonce_save_variations'], 'wcs_subscription_variations' ) ) { - return; - } + add_action( + 'woocommerce_save_product_variation', + function( $variation_id ) use ( $c ) { + $wcsnonce_save_variations = wc_clean( wp_unslash( $_POST['_wcsnonce_save_variations'] ?? '' ) ); + if ( ! WC_Subscriptions_Product::is_subscription( $variation_id ) || empty( $wcsnonce_save_variations ) || ! wp_verify_nonce( $wcsnonce_save_variations, 'wcs_subscription_variations' ) ) { + return; + } - $product = wc_get_product( $variation_id ); - if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) { - return; - } + $product = wc_get_product( $variation_id ); + if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) { + return; + } - $subscriptions_api_handler = $c->get('subscription.api-handler'); - assert($subscriptions_api_handler instanceof SubscriptionsApiHandler); - $this->update_subscription_product_meta($product, $subscriptions_api_handler); - }); + $subscriptions_api_handler = $c->get( 'subscription.api-handler' ); + assert( $subscriptions_api_handler instanceof SubscriptionsApiHandler ); + $this->update_subscription_product_meta( $product, $subscriptions_api_handler ); + } + ); add_action( 'woocommerce_process_shop_subscription_meta', @@ -839,16 +841,7 @@ class SubscriptionModule implements ModuleInterface { * @return void */ private function render_paypal_subscription_fields( WC_Product $product, Environment $environment ): void { - if(is_a($product, WC_Product_Variable_Subscription::class)) { - $variations = $product->get_available_variations(); - foreach ($variations as $variation) { - $a = 1; - // $variation['variation_id'] - } - } - $enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' ); - $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); echo '

'; echo sprintf( @@ -868,14 +861,15 @@ class SubscriptionModule implements ModuleInterface { echo wc_help_tip( esc_html__( 'Create a subscription product and plan to bill customers at regular intervals. Be aware that certain subscription settings cannot be modified once the PayPal Subscription is linked to this product. Unlink the product to edit disabled fields.', 'woocommerce-paypal-payments' ) ); echo '

'; - $subscription_product = $product->get_meta( 'ppcp_subscription_product' ); - $subscription_plan = $product->get_meta( 'ppcp_subscription_plan' ); + $subscription_product = $product->get_meta( 'ppcp_subscription_product' ); + $subscription_plan = $product->get_meta( 'ppcp_subscription_plan' ); + $subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' ); if ( $subscription_product && $subscription_plan ) { if ( $enable_subscription_product !== 'yes' ) { echo sprintf( // translators: %1$s and %2$s are button and wrapper html tags. esc_html__( '%1$sUnlink PayPal Subscription Plan%2$s', 'woocommerce-paypal-payments' ), - '

' ); echo sprintf( @@ -912,38 +906,62 @@ class SubscriptionModule implements ModuleInterface { /** * Updates subscription product meta. * - * @param WC_Product $product - * @param SubscriptionsApiHandler $subscriptions_api_handler + * @param WC_Product $product The product. + * @param SubscriptionsApiHandler $subscriptions_api_handler The subscription api handler. * @return void */ - private function update_subscription_product_meta(WC_Product $product, SubscriptionsApiHandler $subscriptions_api_handler): void - { - $enable_subscription_product = wc_clean(wp_unslash($_POST['_ppcp_enable_subscription_product'] ?? '')); - $product->update_meta_data('_ppcp_enable_subscription_product', $enable_subscription_product); + private function update_subscription_product_meta( WC_Product $product, SubscriptionsApiHandler $subscriptions_api_handler ): void { + // phpcs:ignore WordPress.Security.NonceVerification + $enable_subscription_product = wc_clean( wp_unslash( $_POST['_ppcp_enable_subscription_product'] ?? '' ) ); + $product->update_meta_data( '_ppcp_enable_subscription_product', $enable_subscription_product ); $product->save(); - if (($product->get_type() === 'subscription' || $product->get_type() === 'subscription_variation') && $enable_subscription_product === 'yes') { - if ($product->meta_exists('ppcp_subscription_product') && $product->meta_exists('ppcp_subscription_plan')) { - $subscriptions_api_handler->update_product($product); - $subscriptions_api_handler->update_plan($product); + if ( ( $product->get_type() === 'subscription' || $product->get_type() === 'subscription_variation' ) && $enable_subscription_product === 'yes' ) { + if ( $product->meta_exists( 'ppcp_subscription_product' ) && $product->meta_exists( 'ppcp_subscription_plan' ) ) { + $subscriptions_api_handler->update_product( $product ); + $subscriptions_api_handler->update_plan( $product ); return; } - if (!$product->meta_exists('ppcp_subscription_product')) { - $subscriptions_api_handler->create_product($product); + if ( ! $product->meta_exists( 'ppcp_subscription_product' ) ) { + $subscriptions_api_handler->create_product( $product ); } - if ($product->meta_exists('ppcp_subscription_product') && !$product->meta_exists('ppcp_subscription_plan')) { - $subscription_plan_name = wc_clean(wp_unslash($_POST['_ppcp_subscription_plan_name'] ?? '')); - if (!is_string($subscription_plan_name)) { + if ( $product->meta_exists( 'ppcp_subscription_product' ) && ! $product->meta_exists( 'ppcp_subscription_plan' ) ) { + // phpcs:ignore WordPress.Security.NonceVerification + $subscription_plan_name = wc_clean( wp_unslash( $_POST['_ppcp_subscription_plan_name'] ?? '' ) ); + if ( ! is_string( $subscription_plan_name ) ) { return; } - $product->update_meta_data('_ppcp_subscription_plan_name', $subscription_plan_name); + $product->update_meta_data( '_ppcp_subscription_plan_name', $subscription_plan_name ); $product->save(); - $subscriptions_api_handler->create_plan($subscription_plan_name, $product); + $subscriptions_api_handler->create_plan( $subscription_plan_name, $product ); } } } + + /** + * Returns subscription product configuration. + * + * @param WC_Product $product The product. + * @return array + */ + private function set_product_config( WC_Product $product ): array { + $plan = $product->get_meta( 'ppcp_subscription_plan' ) ?? array(); + $plan_id = $plan['id'] ?? ''; + + return array( + 'product_connected' => $product->get_meta( '_ppcp_enable_subscription_product' ) ?? '', + 'ajax' => array( + 'deactivate_plan' => array( + 'endpoint' => \WC_AJAX::get_endpoint( DeactivatePlanEndpoint::ENDPOINT ), + 'nonce' => wp_create_nonce( DeactivatePlanEndpoint::ENDPOINT ), + 'plan_id' => $plan_id, + 'product_id' => $product->get_id(), + ), + ), + ); + } } From 4ed7742d9acb02407ef8d8d0ad0ac8163e5a4b1a Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 18 Jul 2023 17:17:22 +0200 Subject: [PATCH 19/32] Disable variable subscription fields (WIP) --- .../resources/js/paypal-subscription.js | 41 ++++++++++++------- .../src/SubscriptionModule.php | 4 +- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index a00bf57a0..427fdda96 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -1,23 +1,36 @@ document.addEventListener( 'DOMContentLoaded', () => { + const variations = document.querySelector('.woocommerce_variations'); + const disableFields = (productId) => { + if(variations) { + const children = variations.children; + for(let i=0; i < children.length; i++) { + const variableId = children[i].querySelector('h3').getElementsByClassName('variable_post_id')[0].value + if( parseInt(variableId) === productId ) { + children[i].querySelector('.woocommerce_variable_attributes').getElementsByClassName('wc_input_subscription_period_interval')[0].setAttribute('disabled', 'disabled'); + } + + const periodInterval = document.querySelector('#_subscription_period_interval'); + periodInterval.setAttribute('disabled', 'disabled'); + + const subscriptionPeriod = document.querySelector('#_subscription_period'); + subscriptionPeriod.setAttribute('disabled', 'disabled'); + + const subscriptionLength = document.querySelector('._subscription_length_field'); + subscriptionLength.style.display = 'none'; + + const subscriptionTrial = document.querySelector('._subscription_trial_length_field'); + subscriptionTrial.style.display = 'none'; + } + const setupProducts = () => { PayPalCommerceGatewayPayPalSubscriptionProducts?.forEach((product) => { if(product.product_connected === 'yes') { - const periodInterval = document.querySelector('#_subscription_period_interval'); - periodInterval.setAttribute('disabled', 'disabled'); - - const subscriptionPeriod = document.querySelector('#_subscription_period'); - subscriptionPeriod.setAttribute('disabled', 'disabled'); - - const subscriptionLength = document.querySelector('._subscription_length_field'); - subscriptionLength.style.display = 'none'; - - const subscriptionTrial = document.querySelector('._subscription_trial_length_field'); - subscriptionTrial.style.display = 'none'; + disableFields(product.product_id); } - const unlinkBtn = document.getElementById(`ppcp-unlink-sub-plan-${product.ajax.deactivate_plan.product_id}`); + const unlinkBtn = document.getElementById(`ppcp-unlink-sub-plan-${product.product_id}`); unlinkBtn?.addEventListener('click', (event)=>{ event.preventDefault(); unlinkBtn.disabled = true; @@ -32,8 +45,8 @@ document.addEventListener( credentials: 'same-origin', body: JSON.stringify({ nonce: product.ajax.deactivate_plan.nonce, - plan_id: product.ajax.deactivate_plan.plan_id, - product_id: product.ajax.deactivate_plan.product_id + plan_id: product.plan_id, + product_id: product.product_id }) }).then(function (res) { return res.json(); diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 5b2978e35..1ed3d75e5 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -954,12 +954,12 @@ class SubscriptionModule implements ModuleInterface { return array( 'product_connected' => $product->get_meta( '_ppcp_enable_subscription_product' ) ?? '', + 'plan_id' => $plan_id, + 'product_id' => $product->get_id(), 'ajax' => array( 'deactivate_plan' => array( 'endpoint' => \WC_AJAX::get_endpoint( DeactivatePlanEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( DeactivatePlanEndpoint::ENDPOINT ), - 'plan_id' => $plan_id, - 'product_id' => $product->get_id(), ), ), ); From 2273a87659a6a5474227e6e32a3c24fc333c0024 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 18 Jul 2023 17:25:43 +0200 Subject: [PATCH 20/32] Disable variable subscription fields (WIP) --- .../ppcp-subscription/resources/js/paypal-subscription.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index 427fdda96..99c1cd630 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -7,8 +7,12 @@ document.addEventListener( const children = variations.children; for(let i=0; i < children.length; i++) { const variableId = children[i].querySelector('h3').getElementsByClassName('variable_post_id')[0].value - if( parseInt(variableId) === productId ) { - children[i].querySelector('.woocommerce_variable_attributes').getElementsByClassName('wc_input_subscription_period_interval')[0].setAttribute('disabled', 'disabled'); + if (parseInt(variableId) === productId) { + children[i].querySelector('.woocommerce_variable_attributes') + .getElementsByClassName('wc_input_subscription_period_interval')[0] + .setAttribute('disabled', 'disabled'); + } + } } const periodInterval = document.querySelector('#_subscription_period_interval'); From 9ce1f80e90351b32409675f32b2a3cf5b6faad60 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 19 Jul 2023 12:03:16 +0200 Subject: [PATCH 21/32] Adjust form fields display --- .../resources/js/paypal-subscription.js | 12 ++++++++++++ .../ppcp-subscription/src/SubscriptionModule.php | 15 ++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/modules/ppcp-subscription/resources/js/paypal-subscription.js b/modules/ppcp-subscription/resources/js/paypal-subscription.js index 99c1cd630..7d848091f 100644 --- a/modules/ppcp-subscription/resources/js/paypal-subscription.js +++ b/modules/ppcp-subscription/resources/js/paypal-subscription.js @@ -11,6 +11,18 @@ document.addEventListener( children[i].querySelector('.woocommerce_variable_attributes') .getElementsByClassName('wc_input_subscription_period_interval')[0] .setAttribute('disabled', 'disabled'); + children[i].querySelector('.woocommerce_variable_attributes') + .getElementsByClassName('wc_input_subscription_period')[0] + .setAttribute('disabled', 'disabled'); + children[i].querySelector('.woocommerce_variable_attributes') + .getElementsByClassName('wc_input_subscription_trial_length')[0] + .setAttribute('disabled', 'disabled'); + children[i].querySelector('.woocommerce_variable_attributes') + .getElementsByClassName('wc_input_subscription_trial_period')[0] + .setAttribute('disabled', 'disabled'); + children[i].querySelector('.woocommerce_variable_attributes') + .getElementsByClassName('wc_input_subscription_length')[0] + .setAttribute('disabled', 'disabled'); } } } diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index 1ed3d75e5..d2077db06 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -842,12 +842,13 @@ class SubscriptionModule implements ModuleInterface { */ private function render_paypal_subscription_fields( WC_Product $product, Environment $environment ): void { $enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' ); + $style = $product->get_type() === 'subscription_variation' ? 'float:left; width:150px;' : ''; echo '

'; echo sprintf( // translators: %1$s and %2$s are label open and close tags. esc_html__( '%1$sConnect to PayPal%2$s', 'woocommerce-paypal-payments' ), - '

' . esc_attr( $subscription_product['id'] ) . '

' ); echo sprintf( // translators: %1$s and %2$s are wrapper html tags. esc_html__( '%1$sPlan%2$s', 'woocommerce-paypal-payments' ), - '

' . esc_attr( $subscription_plan['id'] ) . '

' ); } else { @@ -954,12 +955,12 @@ class SubscriptionModule implements ModuleInterface { return array( 'product_connected' => $product->get_meta( '_ppcp_enable_subscription_product' ) ?? '', - 'plan_id' => $plan_id, - 'product_id' => $product->get_id(), + 'plan_id' => $plan_id, + 'product_id' => $product->get_id(), 'ajax' => array( 'deactivate_plan' => array( - 'endpoint' => \WC_AJAX::get_endpoint( DeactivatePlanEndpoint::ENDPOINT ), - 'nonce' => wp_create_nonce( DeactivatePlanEndpoint::ENDPOINT ), + 'endpoint' => \WC_AJAX::get_endpoint( DeactivatePlanEndpoint::ENDPOINT ), + 'nonce' => wp_create_nonce( DeactivatePlanEndpoint::ENDPOINT ), ), ), ); From c636192e9842fc53f24969b7da3ad4d8851a724b Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 20 Jul 2023 12:27:14 +0200 Subject: [PATCH 22/32] Do not render buttons on single product page if there is not subscription plan --- .../SingleProductActionHandler.js | 20 +------------------ .../ContextBootstrap/SingleProductBootstap.js | 11 +++++++++- .../js/modules/Helper/Subscriptions.js | 16 +++++++++++++++ 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js index ca913baf5..fb002ebdf 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js @@ -21,25 +21,7 @@ class SingleProductActionHandler { this.cartHelper = null; } - getPlanIdFromVariation = (variation) => { - let subscription_plan = ''; - PayPalCommerceGateway.variable_paypal_subscription_variations.forEach((element) => { - let obj = {}; - variation.forEach(({name, value}) => { - Object.assign(obj, {[name.replace('attribute_', '')]: value}); - }) - - if(JSON.stringify(obj) === JSON.stringify(element.attributes) && element.subscription_plan !== '') { - subscription_plan = element.subscription_plan; - } - }); - - return subscription_plan; - } - - subscriptionsConfiguration(selected_variation = null) { - const subscription_plan = selected_variation !== null ? this.getPlanIdFromVariation(selected_variation) : this.config.subscription_plan_id - + subscriptionsConfiguration(subscription_plan) { return { createSubscription: (data, actions) => { return actions.subscription.create({ diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index 61f167d31..f76ba9c91 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -3,6 +3,7 @@ import SingleProductActionHandler from "../ActionHandler/SingleProductActionHand import {hide, show} from "../Helper/Hiding"; import BootstrapHelper from "../Helper/BootstrapHelper"; import {loadPaypalJsScript} from "../Helper/ScriptLoading"; +import {getPlanIdFromVariation} from "../Helper/Subscriptions" class SingleProductBootstap { constructor(gateway, renderer, messages, errorHandler) { @@ -165,6 +166,14 @@ class SingleProductBootstap { ) { const buttonWrapper = document.getElementById('ppc-button-ppcp-gateway'); buttonWrapper.innerHTML = ''; + + const subscription_plan = this.variations() !== null + ? getPlanIdFromVariation(this.variations()) + : PayPalCommerceGateway.subscription_plan_id + if(!subscription_plan) { + return; + } + loadPaypalJsScript( { clientId: PayPalCommerceGateway.client_id, @@ -172,7 +181,7 @@ class SingleProductBootstap { intent: 'subscription', vault: true }, - actionHandler.subscriptionsConfiguration(this.variations()), + actionHandler.subscriptionsConfiguration(subscription_plan), this.gateway.button.wrapper ); return; diff --git a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js index a205ac459..4366fd9d2 100644 --- a/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js +++ b/modules/ppcp-button/resources/js/modules/Helper/Subscriptions.js @@ -2,3 +2,19 @@ export const isChangePaymentPage = () => { const urlParams = new URLSearchParams(window.location.search) return urlParams.has('change_payment_method'); } + +export const getPlanIdFromVariation = (variation) => { + let subscription_plan = ''; + PayPalCommerceGateway.variable_paypal_subscription_variations.forEach((element) => { + let obj = {}; + variation.forEach(({name, value}) => { + Object.assign(obj, {[name.replace('attribute_', '')]: value}); + }) + + if(JSON.stringify(obj) === JSON.stringify(element.attributes) && element.subscription_plan !== '') { + subscription_plan = element.subscription_plan; + } + }); + + return subscription_plan; +} From c13ac3ab733dca374d60f9196f669962186f4381 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 20 Jul 2023 14:29:37 +0200 Subject: [PATCH 23/32] Disable buttons in cart and checkout pages when no subscription plan exists --- .../resources/js/modules/ContextBootstrap/CartBootstap.js | 6 ++++++ .../js/modules/ContextBootstrap/CheckoutBootstap.js | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index 5aadb7f61..126c28d08 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -77,6 +77,12 @@ class CartBootstrap { && PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled ) { this.renderer.render(actionHandler.subscriptionsConfiguration()); + + if(!PayPalCommerceGateway.subscription_plan_id) { + this.gateway.button.is_disabled = true; + this.handleButtonStatus(); + } + return; } diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js index db1cba84f..ab75d1c16 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js @@ -107,6 +107,12 @@ class CheckoutBootstap { && PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled ) { this.renderer.render(actionHandler.subscriptionsConfiguration(), {}, actionHandler.configuration()); + + if(!PayPalCommerceGateway.subscription_plan_id) { + this.gateway.button.is_disabled = true; + this.handleButtonStatus(); + } + return; } From 686884027634d160b0195efbac0dc7fbc45fc552 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 26 Jul 2023 11:08:09 +0200 Subject: [PATCH 24/32] Add wc rest api library for testing --- .env.e2e.example | 3 + package.json | 3 +- tests/playwright/subscriptions-api.spec.js | 15 +- yarn.lock | 155 +++++++++++++++++++++ 4 files changed, 170 insertions(+), 6 deletions(-) diff --git a/.env.e2e.example b/.env.e2e.example index 98ad27c23..57d94d433 100644 --- a/.env.e2e.example +++ b/.env.e2e.example @@ -3,6 +3,9 @@ PPCP_E2E_WP_DIR=${ROOT_DIR}/.ddev/wordpress BASEURL="https://woocommerce-paypal-payments.ddev.site" AUTHORIZATION="Bearer ABC123" +WC_CONSUMER_KEY="ck_abc123", +WC_CONSUMER_SECRET="cs_def456" + CHECKOUT_URL="/checkout" CHECKOUT_PAGE_ID=7 CART_URL="/cart" diff --git a/package.json b/package.json index 2fd22648b..c3e27161e 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "npm-run-all": "^4.1.5" }, "devDependencies": { - "@playwright/test": "^1.31.1" + "@playwright/test": "^1.31.1", + "@woocommerce/woocommerce-rest-api": "^1.0.1" } } diff --git a/tests/playwright/subscriptions-api.spec.js b/tests/playwright/subscriptions-api.spec.js index 9d5bce889..2b8845dfa 100644 --- a/tests/playwright/subscriptions-api.spec.js +++ b/tests/playwright/subscriptions-api.spec.js @@ -1,4 +1,6 @@ const {test, expect} = require('@playwright/test'); +const wcApi = require('@woocommerce/woocommerce-rest-api').default; + const {loginAsAdmin, loginAsCustomer} = require('./utils/user'); const {openPaypalPopup, loginIntoPaypal, completePaypalPayment} = require("./utils/paypal-popup"); const {fillCheckoutForm, expectOrderReceivedPage} = require("./utils/checkout"); @@ -7,6 +9,9 @@ const { SUBSCRIPTION_URL, CHECKOUT_URL, CART_URL, + BASEURL, + WC_CONSUMER_KEY, + WC_CONSUMER_SECRET, } = process.env; async function purchaseSubscriptionFromCart(page) { @@ -18,7 +23,7 @@ async function purchaseSubscriptionFromCart(page) { const popup = await openPaypalPopup(page); await loginIntoPaypal(popup); - await popup.getByText('Continue', { exact: true }).click(); + await popup.getByText('Continue', {exact: true}).click(); await popup.locator('#confirmButtonTop').click(); await fillCheckoutForm(page); @@ -92,7 +97,7 @@ test.describe.serial('Subscriptions Merchant', () => { await loginAsAdmin(page); await page.goto('/wp-admin/edit.php?post_type=product'); - await page.getByRole('link', { name: productTitle, exact: true }).click(); + await page.getByRole('link', {name: productTitle, exact: true}).click(); await page.fill('#title', `Updated ${productTitle}`); await page.fill('#_subscription_price', '20'); @@ -209,7 +214,7 @@ test.describe('Subscriber purchase a Subscription', () => { const popup = await openPaypalPopup(page); await loginIntoPaypal(popup); - await popup.getByText('Continue', { exact: true }).click(); + await popup.getByText('Continue', {exact: true}).click(); await Promise.all([ page.waitForNavigation(), @@ -226,7 +231,7 @@ test.describe('Subscriber purchase a Subscription', () => { const popup = await openPaypalPopup(page); await loginIntoPaypal(popup); - await popup.getByText('Continue', { exact: true }).click(); + await popup.getByText('Continue', {exact: true}).click(); await popup.locator('#confirmButtonTop').click(); await fillCheckoutForm(page); @@ -308,4 +313,4 @@ test.describe('Subscriber my account actions', () => { details = await subscription.json(); await expect(details.status).toBe('CANCELLED'); }); -}) ; +}); diff --git a/yarn.lock b/yarn.lock index 89ead66f1..0b3914349 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,6 +17,16 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.1.tgz#90dad8476f1e42797c49d6f8b69aaf9f876fc69f" integrity sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ== +"@woocommerce/woocommerce-rest-api@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@woocommerce/woocommerce-rest-api/-/woocommerce-rest-api-1.0.1.tgz#112b998e8e3758203a71d5e3e0b24efcb1cff842" + integrity sha512-YBk3EEYE0zax/egx6Rhpbu6hcCFyZpYQrjH9JO4NUGU3n3T0W9Edn7oAUbjL/c7Oezcg+UaQluCaKjY/B3zwxg== + dependencies: + axios "^0.19.0" + create-hmac "^1.1.7" + oauth-1.0a "^2.2.6" + url-parse "^1.4.7" + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -24,6 +34,13 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +axios@^0.19.0: + version "0.19.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" + integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== + dependencies: + follow-redirects "1.5.10" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -54,6 +71,14 @@ chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -71,6 +96,29 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +create-hash@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -82,6 +130,13 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + define-properties@^1.1.3, define-properties@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" @@ -146,6 +201,13 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + fsevents@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" @@ -229,11 +291,25 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -350,6 +426,15 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -362,6 +447,11 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -392,6 +482,11 @@ npm-run-all@^4.1.5: shell-quote "^1.6.1" string.prototype.padend "^3.0.0" +oauth-1.0a@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/oauth-1.0a/-/oauth-1.0a-2.2.6.tgz#eadbccdb3bceea412d24586e6f39b2b412f0e491" + integrity sha512-6bkxv3N4Gu5lty4viIcIAnq5GbxECviMBeKR3WX/q87SPQ8E8aursPZUtsXDnxCs787af09WPRBLqYrf/lwoYQ== + object-inspect@^1.12.2, object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" @@ -452,6 +547,11 @@ playwright-core@1.31.1: resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.31.1.tgz#4deeebbb8fb73b512593fe24bea206d8fd85ff7f" integrity sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -461,6 +561,15 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" @@ -470,6 +579,11 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + resolve@^1.10.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" @@ -479,6 +593,19 @@ resolve@^1.10.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" @@ -493,6 +620,14 @@ safe-regex-test@^1.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -572,6 +707,13 @@ string.prototype.trimstart@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -599,6 +741,19 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +url-parse@^1.4.7: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" From b07619c2725b8ae20dca8920b37b50b00ed42b4e Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 27 Jul 2023 12:55:01 +0200 Subject: [PATCH 25/32] Add tests for subscription buttons display (WIP) --- .env.e2e.example | 3 - playwright.config.js | 2 +- tests/playwright/subscriptions-api.spec.js | 67 ++++++++++++++++++++-- tests/playwright/utils/product.js | 59 +++++++++++++++++++ 4 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 tests/playwright/utils/product.js diff --git a/.env.e2e.example b/.env.e2e.example index 57d94d433..98ad27c23 100644 --- a/.env.e2e.example +++ b/.env.e2e.example @@ -3,9 +3,6 @@ PPCP_E2E_WP_DIR=${ROOT_DIR}/.ddev/wordpress BASEURL="https://woocommerce-paypal-payments.ddev.site" AUTHORIZATION="Bearer ABC123" -WC_CONSUMER_KEY="ck_abc123", -WC_CONSUMER_SECRET="cs_def456" - CHECKOUT_URL="/checkout" CHECKOUT_PAGE_ID=7 CART_URL="/cart" diff --git a/playwright.config.js b/playwright.config.js index 6ade8826a..1a1663f2e 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -2,7 +2,7 @@ require('dotenv').config({ path: '.env.e2e' }); const config = { testDir: './tests/playwright', - timeout: 60000, + timeout: 30000, use: { baseURL: process.env.BASEURL, ignoreHTTPSErrors: true, diff --git a/tests/playwright/subscriptions-api.spec.js b/tests/playwright/subscriptions-api.spec.js index 2b8845dfa..d1970e328 100644 --- a/tests/playwright/subscriptions-api.spec.js +++ b/tests/playwright/subscriptions-api.spec.js @@ -1,17 +1,14 @@ const {test, expect} = require('@playwright/test'); -const wcApi = require('@woocommerce/woocommerce-rest-api').default; const {loginAsAdmin, loginAsCustomer} = require('./utils/user'); const {openPaypalPopup, loginIntoPaypal, completePaypalPayment} = require("./utils/paypal-popup"); const {fillCheckoutForm, expectOrderReceivedPage} = require("./utils/checkout"); +const {createProduct, deleteProduct, updateProduct, updateProductUi} = require("./utils/product"); const { AUTHORIZATION, SUBSCRIPTION_URL, CHECKOUT_URL, CART_URL, - BASEURL, - WC_CONSUMER_KEY, - WC_CONSUMER_SECRET, } = process.env; async function purchaseSubscriptionFromCart(page) { @@ -314,3 +311,65 @@ test.describe('Subscriber my account actions', () => { await expect(details.status).toBe('CANCELLED'); }); }); + +test('Disable buttons if no plan connected', async ({page}) => { + const data = { + name: 'Subscription', + type: 'subscription', + meta_data: [ + { + key: '_subscription_price', + value: '10' + } + ] + } + const productId = await createProduct(data) + + // for some reason product meta is not updated in frontend, + // so we need to manually update the product + await updateProductUi(productId, page); + + await page.goto('/product/subscription') + await expect(page.locator('#ppc-button-ppcp-gateway')).not.toBeVisible(); + + await page.locator('.single_add_to_cart_button').click(); + await page.goto('/cart'); + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + await expect(page.locator('#ppc-button-ppcp-gateway')).toHaveCSS('cursor', 'not-allowed') + + await page.goto('/checkout'); + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + await expect(page.locator('#ppc-button-ppcp-gateway')).toHaveCSS('cursor', 'not-allowed') + + await deleteProduct(productId) +}) + +test('Enable buttons if plan connected', async ({page}) => { + const data = { + name: 'Subscription', + type: 'subscription', + meta_data: [ + { + key: '_subscription_price', + value: '10' + } + ] + } + const productId = await createProduct(data) + + await loginAsAdmin(page); + await page.goto(`/wp-admin/post.php?post=${productId}&action=edit`) + await page.locator('#ppcp_enable_subscription_product').check(); + await page.locator('#ppcp_subscription_plan_name').fill('Plan name'); + await page.locator('#publish').click(); + await expect(page.getByText('Product updated.')).toBeVisible(); + + await page.goto('/product/subscription') + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + + await page.getByText('Sign up now').click(); + await page.goto('/cart'); + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + + await deleteProduct(productId) +}) diff --git a/tests/playwright/utils/product.js b/tests/playwright/utils/product.js new file mode 100644 index 000000000..65fbdbe2e --- /dev/null +++ b/tests/playwright/utils/product.js @@ -0,0 +1,59 @@ +import {loginAsAdmin} from "./user"; +import {expect} from "@playwright/test"; + +const wcApi = require('@woocommerce/woocommerce-rest-api').default; +const { + BASEURL, + WP_MERCHANT_USER, + WP_MERCHANT_PASSWORD, +} = process.env; + +const wc = () => { + return new wcApi({ + url: BASEURL, + consumerKey: WP_MERCHANT_USER, + consumerSecret: WP_MERCHANT_PASSWORD, + version: 'wc/v3', + }); +} + +export const createProduct = async (data) => { + const api = wc(); + + return await api.post('products', data) + .then((response) => { + return response.data.id + }).catch((error) => { + console.log(error) + }) +} + +export const updateProduct = async (data, id) => { + const api = wc(); + + return await api.put(`products/${id}`, data) + .then((response) => { + return response.data.id + }).catch((error) => { + console.log(error) + }) +} + +export const deleteProduct = async (id) => { + const api = wc(); + + return await api.delete(`products/${id}`) + .then((response) => { + return response.data.id + }).catch((error) => { + console.log(error) + }) +} + +export const updateProductUi = async (id, page) => { + await loginAsAdmin(page); + await page.goto(`/wp-admin/post.php?post=${id}&action=edit`) + await page.locator('#publish').click(); + await expect(page.getByText('Product updated.')).toBeVisible(); +} + From 65c50e0888139b66bb33db355dc1d6830f642801 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Thu, 27 Jul 2023 16:07:43 +0200 Subject: [PATCH 26/32] Remove parenthesis in test name othewise does not work when run test individually --- tests/playwright/place-order.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/playwright/place-order.spec.js b/tests/playwright/place-order.spec.js index c0228c351..4a9f7523f 100644 --- a/tests/playwright/place-order.spec.js +++ b/tests/playwright/place-order.spec.js @@ -65,7 +65,7 @@ test.describe('Classic checkout', () => { await expectOrderReceivedPage(page); }); - test('Advanced Credit and Debit Card (ACDC) place order from Checkout page', async ({page}) => { + test('Advanced Credit and Debit Card place order from Checkout page', async ({page}) => { await page.goto(PRODUCT_URL); await page.locator('.single_add_to_cart_button').click(); From 59b583b7aae267cdb9adc7bb08ab55cdcc5e051e Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 7 Aug 2023 15:27:17 +0200 Subject: [PATCH 27/32] Add products utility test --- tests/Playwright/package.json | 5 +- tests/Playwright/playwright.config.js | 1 + .../tests/subscriptions-api.spec.js | 114 +++++++++--------- tests/Playwright/tests/utils/products.js | 59 +++++++++ 4 files changed, 122 insertions(+), 57 deletions(-) create mode 100644 tests/Playwright/tests/utils/products.js diff --git a/tests/Playwright/package.json b/tests/Playwright/package.json index 7b12a8f11..e2e3e6465 100644 --- a/tests/Playwright/package.json +++ b/tests/Playwright/package.json @@ -1,7 +1,8 @@ { "license": "MIT", "dependencies": { - "@playwright/test": "^1.34.2", - "dotenv": "^16.0.3" + "@playwright/test": "^1.34.2", + "@woocommerce/woocommerce-rest-api": "^1.0.1", + "dotenv": "^16.0.3" } } diff --git a/tests/Playwright/playwright.config.js b/tests/Playwright/playwright.config.js index d7e8f4928..dbe3173da 100644 --- a/tests/Playwright/playwright.config.js +++ b/tests/Playwright/playwright.config.js @@ -7,6 +7,7 @@ require('dotenv').config({ path: '.env' }); * @see https://playwright.dev/docs/test-configuration */ module.exports = defineConfig({ + timeout: 60000, testDir: './tests', /* Run tests in files in parallel */ fullyParallel: true, diff --git a/tests/Playwright/tests/subscriptions-api.spec.js b/tests/Playwright/tests/subscriptions-api.spec.js index d1970e328..fe79ccad9 100644 --- a/tests/Playwright/tests/subscriptions-api.spec.js +++ b/tests/Playwright/tests/subscriptions-api.spec.js @@ -3,7 +3,7 @@ const {test, expect} = require('@playwright/test'); const {loginAsAdmin, loginAsCustomer} = require('./utils/user'); const {openPaypalPopup, loginIntoPaypal, completePaypalPayment} = require("./utils/paypal-popup"); const {fillCheckoutForm, expectOrderReceivedPage} = require("./utils/checkout"); -const {createProduct, deleteProduct, updateProduct, updateProductUi} = require("./utils/product"); +const {createProduct, deleteProduct, updateProduct, updateProductUi} = require("./utils/products"); const { AUTHORIZATION, SUBSCRIPTION_URL, @@ -312,64 +312,68 @@ test.describe('Subscriber my account actions', () => { }); }); -test('Disable buttons if no plan connected', async ({page}) => { - const data = { - name: 'Subscription', - type: 'subscription', - meta_data: [ - { - key: '_subscription_price', - value: '10' - } - ] - } - const productId = await createProduct(data) +test.describe('Plan connected display buttons', () => { + test('Disable buttons if no plan connected', async ({page}) => { + const data = { + name: (Math.random() + 1).toString(36).substring(7), + type: 'subscription', + meta_data: [ + { + key: '_subscription_price', + value: '10' + } + ] + } + const productId = await createProduct(data) - // for some reason product meta is not updated in frontend, - // so we need to manually update the product - await updateProductUi(productId, page); + // for some reason product meta is not updated in frontend, + // so we need to manually update the product + await updateProductUi(productId, page); - await page.goto('/product/subscription') - await expect(page.locator('#ppc-button-ppcp-gateway')).not.toBeVisible(); + await page.goto(`/product/?p=${productId}`) + await expect(page.locator('#ppc-button-ppcp-gateway')).not.toBeVisible(); - await page.locator('.single_add_to_cart_button').click(); - await page.goto('/cart'); - await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); - await expect(page.locator('#ppc-button-ppcp-gateway')).toHaveCSS('cursor', 'not-allowed') + await page.locator('.single_add_to_cart_button').click(); + await page.goto('/cart'); + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + await expect(page.locator('#ppc-button-ppcp-gateway')).toHaveCSS('cursor', 'not-allowed') - await page.goto('/checkout'); - await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); - await expect(page.locator('#ppc-button-ppcp-gateway')).toHaveCSS('cursor', 'not-allowed') + await page.goto('/checkout'); + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + await expect(page.locator('#ppc-button-ppcp-gateway')).toHaveCSS('cursor', 'not-allowed') - await deleteProduct(productId) + await deleteProduct(productId) + }) + + test('Enable buttons if plan connected', async ({page}) => { + const data = { + name: (Math.random() + 1).toString(36).substring(7), + type: 'subscription', + meta_data: [ + { + key: '_subscription_price', + value: '10' + } + ] + } + const productId = await createProduct(data) + + await loginAsAdmin(page); + await page.goto(`/wp-admin/post.php?post=${productId}&action=edit`) + await page.locator('#ppcp_enable_subscription_product').check(); + await page.locator('#ppcp_subscription_plan_name').fill('Plan name'); + await page.locator('#publish').click(); + await expect(page.getByText('Product updated.')).toBeVisible(); + + await page.goto(`/product/?p=${productId}`) + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + + //await page.getByText('Sign up now').click(); + await page.locator('.single_add_to_cart_button').click(); + await page.goto('/cart'); + await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); + + await deleteProduct(productId) + }) }) -test('Enable buttons if plan connected', async ({page}) => { - const data = { - name: 'Subscription', - type: 'subscription', - meta_data: [ - { - key: '_subscription_price', - value: '10' - } - ] - } - const productId = await createProduct(data) - - await loginAsAdmin(page); - await page.goto(`/wp-admin/post.php?post=${productId}&action=edit`) - await page.locator('#ppcp_enable_subscription_product').check(); - await page.locator('#ppcp_subscription_plan_name').fill('Plan name'); - await page.locator('#publish').click(); - await expect(page.getByText('Product updated.')).toBeVisible(); - - await page.goto('/product/subscription') - await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); - - await page.getByText('Sign up now').click(); - await page.goto('/cart'); - await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); - - await deleteProduct(productId) -}) diff --git a/tests/Playwright/tests/utils/products.js b/tests/Playwright/tests/utils/products.js new file mode 100644 index 000000000..65fbdbe2e --- /dev/null +++ b/tests/Playwright/tests/utils/products.js @@ -0,0 +1,59 @@ +import {loginAsAdmin} from "./user"; +import {expect} from "@playwright/test"; + +const wcApi = require('@woocommerce/woocommerce-rest-api').default; +const { + BASEURL, + WP_MERCHANT_USER, + WP_MERCHANT_PASSWORD, +} = process.env; + +const wc = () => { + return new wcApi({ + url: BASEURL, + consumerKey: WP_MERCHANT_USER, + consumerSecret: WP_MERCHANT_PASSWORD, + version: 'wc/v3', + }); +} + +export const createProduct = async (data) => { + const api = wc(); + + return await api.post('products', data) + .then((response) => { + return response.data.id + }).catch((error) => { + console.log(error) + }) +} + +export const updateProduct = async (data, id) => { + const api = wc(); + + return await api.put(`products/${id}`, data) + .then((response) => { + return response.data.id + }).catch((error) => { + console.log(error) + }) +} + +export const deleteProduct = async (id) => { + const api = wc(); + + return await api.delete(`products/${id}`) + .then((response) => { + return response.data.id + }).catch((error) => { + console.log(error) + }) +} + +export const updateProductUi = async (id, page) => { + await loginAsAdmin(page); + await page.goto(`/wp-admin/post.php?post=${id}&action=edit`) + await page.locator('#publish').click(); + await expect(page.getByText('Product updated.')).toBeVisible(); +} + From cb19889728c79e64dd590df3f48a54e1312ecb4a Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 7 Aug 2023 16:53:44 +0200 Subject: [PATCH 28/32] Add subscription path to build assest scripts --- package.json | 3 +++ tests/Playwright/tests/subscriptions-api.spec.js | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ef26f7239..19c9fee2b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "install:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn install", "install:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn install", "install:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn install", + "install:modules:ppcp-subscription": "cd modules/ppcp-subscription && yarn install", "install:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn install", "install:modules:ppcp-compat": "cd modules/ppcp-compat && yarn install", "install:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn install", @@ -20,6 +21,7 @@ "build:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run build", "build:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run build", "build:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn run build", + "build:modules:ppcp-subscription": "cd modules/ppcp-subscription && yarn run build", "build:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn run build", "build:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run build", "build:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run build", @@ -29,6 +31,7 @@ "watch:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run watch", "watch:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run watch", "watch:modules:ppcp-order-tracking": "cd modules/ppcp-order-tracking && yarn run watch", + "watch:modules:ppcp-subscription": "cd modules/ppcp-subscription && yarn run watch", "watch:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn run watch", "watch:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run watch", "watch:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run watch", diff --git a/tests/Playwright/tests/subscriptions-api.spec.js b/tests/Playwright/tests/subscriptions-api.spec.js index fe79ccad9..d575ed8f7 100644 --- a/tests/Playwright/tests/subscriptions-api.spec.js +++ b/tests/Playwright/tests/subscriptions-api.spec.js @@ -368,7 +368,6 @@ test.describe('Plan connected display buttons', () => { await page.goto(`/product/?p=${productId}`) await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); - //await page.getByText('Sign up now').click(); await page.locator('.single_add_to_cart_button').click(); await page.goto('/cart'); await expect(page.locator('#ppc-button-ppcp-gateway')).toBeVisible(); From be8015b8ddc2fcf0d436bef0532d10534f94c35c Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Mon, 7 Aug 2023 18:53:01 +0200 Subject: [PATCH 29/32] Add variations get subscription products --- .../js/modules/ActionHandler/SingleProductActionHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js index b751740ef..68bf43e81 100644 --- a/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js +++ b/modules/ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler.js @@ -73,7 +73,7 @@ class SingleProductActionHandler { getSubscriptionProducts() { const id = document.querySelector('[name="add-to-cart"]').value; - return [new Product(id, 1, [])]; + return [new Product(id, 1, this.variations())]; } configuration() From 02e35bbe9d8bdd1f7b64abf772ee8e77bf433a07 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 8 Aug 2023 12:10:31 +0200 Subject: [PATCH 30/32] Prevent PayPal subscription buttons to be rendered multiple times --- .../js/modules/ContextBootstrap/SingleProductBootstap.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js index cc6407ccf..54f3f931f 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/SingleProductBootstap.js @@ -22,6 +22,8 @@ class SingleProductBootstap { this.renderer.onButtonsInit(this.gateway.button.wrapper, () => { this.handleChange(); }, true); + + this.subscriptionButtonsLoaded = false } form() { @@ -29,6 +31,8 @@ class SingleProductBootstap { } handleChange() { + this.subscriptionButtonsLoaded = false + if (!this.shouldRender()) { this.renderer.disableSmartButtons(this.gateway.button.wrapper); hide(this.gateway.button.wrapper, this.formSelector); @@ -187,6 +191,7 @@ class SingleProductBootstap { return; } + if(this.subscriptionButtonsLoaded) return loadPaypalJsScript( { clientId: PayPalCommerceGateway.client_id, @@ -197,6 +202,8 @@ class SingleProductBootstap { actionHandler.subscriptionsConfiguration(subscription_plan), this.gateway.button.wrapper ); + + this.subscriptionButtonsLoaded = true return; } From 4d8302be453314a0a1d0184320792218148adab0 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Tue, 8 Aug 2023 12:53:14 +0200 Subject: [PATCH 31/32] Fix psalm --- .psalm/wcs.php | 14 +++++++++++ .../src/Helper/SubscriptionHelper.php | 19 ++++++++------ .../src/SubscriptionModule.php | 25 +++++++++++++++++-- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/.psalm/wcs.php b/.psalm/wcs.php index a35088c88..cc33e0103 100644 --- a/.psalm/wcs.php +++ b/.psalm/wcs.php @@ -2093,3 +2093,17 @@ function wcs_order_contains_product($order, $product) * @return string Page ID. Empty string if resource not found. */ function wc_get_page_screen_id( $for ) {} + +/** + * Subscription Product Variation Class + * + * The subscription product variation class extends the WC_Product_Variation product class + * to create subscription product variations. + * + * @class WC_Product_Subscription + * @package WooCommerce Subscriptions + * @category Class + * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3 + * + */ +class WC_Product_Subscription_Variation extends WC_Product_Variation {} diff --git a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php index 619fbc658..635e66cc1 100644 --- a/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php +++ b/modules/ppcp-subscription/src/Helper/SubscriptionHelper.php @@ -219,6 +219,11 @@ class SubscriptionHelper { return ''; } + /** + * Returns variations for variable PayPal subscription product. + * + * @return array + */ public function variable_paypal_subscription_variations(): array { $variations = array(); if ( ! $this->current_product_is_subscription() ) { @@ -232,16 +237,16 @@ class SubscriptionHelper { } $variation_ids = $product->get_children(); - foreach ($variation_ids as $id) { - $product = wc_get_product($id); - if(! is_a($product, WC_Product_Subscription_Variation::class )) { + foreach ( $variation_ids as $id ) { + $product = wc_get_product( $id ); + if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) { continue; } - $subscription_plan = $product->get_meta('ppcp_subscription_plan') ?? ''; - $variations[] = array( - 'id' => $product->get_id(), - 'attributes' => $product->get_attributes(), + $subscription_plan = $product->get_meta( 'ppcp_subscription_plan' ) ?? array(); + $variations[] = array( + 'id' => $product->get_id(), + 'attributes' => $product->get_attributes(), 'subscription_plan' => $subscription_plan['id'] ?? '', ); } diff --git a/modules/ppcp-subscription/src/SubscriptionModule.php b/modules/ppcp-subscription/src/SubscriptionModule.php index d2077db06..5fe6f1dc1 100644 --- a/modules/ppcp-subscription/src/SubscriptionModule.php +++ b/modules/ppcp-subscription/src/SubscriptionModule.php @@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Subscription; use Exception; use WC_Product; use WC_Product_Subscription_Variation; +use WC_Product_Variable; use WC_Product_Variable_Subscription; use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions; @@ -195,9 +196,15 @@ class SubscriptionModule implements ModuleInterface { $products = array( $this->set_product_config( $product ) ); if ( $product->get_type() === 'variable-subscription' ) { - $products = array(); + $products = array(); + assert( $product instanceof WC_Product_Variable ); $available_variations = $product->get_available_variations(); foreach ( $available_variations as $variation ) { + /** + * The method is defined in WooCommerce. + * + * @psalm-suppress UndefinedMethod + */ $variation = wc_get_product_object( 'variation', $variation['variation_id'] ); $products[] = $this->set_product_config( $variation ); } @@ -472,9 +479,18 @@ class SubscriptionModule implements ModuleInterface { add_action( 'woocommerce_save_product_variation', + /** + * Param types removed to avoid third-party issues. + * + * @psalm-suppress MissingClosureParamType + */ function( $variation_id ) use ( $c ) { $wcsnonce_save_variations = wc_clean( wp_unslash( $_POST['_wcsnonce_save_variations'] ?? '' ) ); - if ( ! WC_Subscriptions_Product::is_subscription( $variation_id ) || empty( $wcsnonce_save_variations ) || ! wp_verify_nonce( $wcsnonce_save_variations, 'wcs_subscription_variations' ) ) { + if ( + ! WC_Subscriptions_Product::is_subscription( $variation_id ) + || ! is_string( $wcsnonce_save_variations ) + || ! wp_verify_nonce( $wcsnonce_save_variations, 'wcs_subscription_variations' ) + ) { return; } @@ -808,6 +824,11 @@ class SubscriptionModule implements ModuleInterface { add_action( 'woocommerce_variation_options_pricing', + /** + * Param types removed to avoid third-party issues. + * + * @psalm-suppress MissingClosureParamType + */ function( $loop, $variation_data, $variation ) use ( $c ) { $settings = $c->get( 'wcgateway.settings' ); assert( $settings instanceof Settings ); From 4260dce97b3244093d9091761f26a0fbd5462d6a Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 9 Aug 2023 15:38:46 +0200 Subject: [PATCH 32/32] Enable buttons when cart contains only one subscription product --- .../resources/js/modules/ContextBootstrap/CartBootstap.js | 2 +- .../js/modules/ContextBootstrap/CheckoutBootstap.js | 2 +- modules/ppcp-button/src/Assets/SmartButton.php | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js index ad4547819..1deaafd54 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CartBootstap.js @@ -87,7 +87,7 @@ class CartBootstrap { ) { this.renderer.render(actionHandler.subscriptionsConfiguration()); - if(!PayPalCommerceGateway.subscription_plan_id) { + if(!PayPalCommerceGateway.subscription_product_allowed) { this.gateway.button.is_disabled = true; this.handleButtonStatus(); } diff --git a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js index 5d770b91e..eb9aa3885 100644 --- a/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js +++ b/modules/ppcp-button/resources/js/modules/ContextBootstrap/CheckoutBootstap.js @@ -107,7 +107,7 @@ class CheckoutBootstap { ) { this.renderer.render(actionHandler.subscriptionsConfiguration(), {}, actionHandler.configuration()); - if(!PayPalCommerceGateway.subscription_plan_id) { + if(!PayPalCommerceGateway.subscription_product_allowed) { this.gateway.button.is_disabled = true; this.handleButtonStatus(); } diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index 1227e233a..fa7c4e23f 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -828,9 +828,9 @@ class SmartButton implements SmartButtonInterface { 'has_subscriptions' => $this->has_subscriptions(), 'paypal_subscriptions_enabled' => $this->paypal_subscriptions_enabled(), ), - 'redirect' => wc_get_checkout_url(), - 'context' => $this->context(), - 'ajax' => array( + 'redirect' => wc_get_checkout_url(), + 'context' => $this->context(), + 'ajax' => array( 'simulate_cart' => array( 'endpoint' => \WC_AJAX::get_endpoint( SimulateCartEndpoint::ENDPOINT ), 'nonce' => wp_create_nonce( SimulateCartEndpoint::nonce() ), @@ -869,6 +869,7 @@ class SmartButton implements SmartButtonInterface { ), 'subscription_plan_id' => $this->subscription_helper->paypal_subscription_id(), 'variable_paypal_subscription_variations' => $this->subscription_helper->variable_paypal_subscription_variations(), + 'subscription_product_allowed' => $this->subscription_helper->checkout_subscription_product_allowed(), 'enforce_vault' => $this->has_subscriptions(), 'can_save_vault_token' => $this->can_save_vault_token(), 'is_free_trial_cart' => $is_free_trial_cart,