From 47386e18c251b62f7dd39e0c5446941e696acde0 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Mon, 19 Aug 2024 13:45:13 +0100 Subject: [PATCH 001/185] Classic cart: Remove common query string variables which affect cart contents (#50725) * Remove common query string variables which affect cart contents * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions --- .../changelog/50725-fix-cart-url-with-query-string | 4 ++++ plugins/woocommerce/includes/wc-core-functions.php | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 plugins/woocommerce/changelog/50725-fix-cart-url-with-query-string diff --git a/plugins/woocommerce/changelog/50725-fix-cart-url-with-query-string b/plugins/woocommerce/changelog/50725-fix-cart-url-with-query-string new file mode 100644 index 00000000000..8db7df8e997 --- /dev/null +++ b/plugins/woocommerce/changelog/50725-fix-cart-url-with-query-string @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak +Comment: Removes querystrings from cart URL introduced in #50524. + diff --git a/plugins/woocommerce/includes/wc-core-functions.php b/plugins/woocommerce/includes/wc-core-functions.php index eb399b895d3..764e32cb4d3 100644 --- a/plugins/woocommerce/includes/wc-core-functions.php +++ b/plugins/woocommerce/includes/wc-core-functions.php @@ -1476,8 +1476,9 @@ function wc_transaction_query( $type = 'start', $force = false ) { */ function wc_get_cart_url() { if ( is_cart() && isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) { - $protocol = is_ssl() ? 'https' : 'http'; - $cart_url = esc_url_raw( $protocol . '://' . wp_unslash( $_SERVER['HTTP_HOST'] ) . wp_unslash( $_SERVER['REQUEST_URI'] ) ); + $protocol = is_ssl() ? 'https' : 'http'; + $current_url = esc_url_raw( $protocol . '://' . wp_unslash( $_SERVER['HTTP_HOST'] ) . wp_unslash( $_SERVER['REQUEST_URI'] ) ); + $cart_url = remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart', 'order_again', '_wpnonce' ), $current_url ); } else { $cart_url = wc_get_page_permalink( 'cart' ); } From d7783511fffc1279bcad199ae0a05be9fb160c73 Mon Sep 17 00:00:00 2001 From: Gabriel Manussakis <9420947+Manussakis@users.noreply.github.com> Date: Mon, 19 Aug 2024 09:57:38 -0300 Subject: [PATCH 002/185] [WIP][Accessibility] Fix inline documentation typos in woocommerce-blocks (#50737) * Fix inline documentation typos in woocommerce-blocks * Add changelog file * Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce * Remove original changelog --------- Co-authored-by: github-actions Co-authored-by: Mike Jolley --- .../assets/js/atomic/blocks/product-elements/price/block.tsx | 2 +- .../assets/js/atomic/blocks/product-elements/sku/edit.tsx | 2 +- .../atomic/blocks/product-elements/stock-indicator/edit.tsx | 2 +- .../assets/js/base/components/block-error-boundary/types.ts | 4 ++-- .../assets/js/base/components/price-slider/index.tsx | 2 +- .../js/base/context/hooks/collections/use-collection.ts | 2 +- .../assets/js/base/context/hooks/test/use-query-state.jsx | 2 +- .../assets/js/blocks/active-filters/block.tsx | 2 +- .../assets/js/blocks/cart-checkout-shared/hacks.ts | 2 +- plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts | 2 +- .../editor-components/search-list-control/test/hierarchy.js | 2 +- plugins/woocommerce-blocks/assets/js/interactivity/vdom.js | 2 +- plugins/woocommerce-blocks/bin/gen-block-list-doc.js | 4 ++-- plugins/woocommerce-blocks/phpcs.xml | 2 +- plugins/woocommerce-blocks/readme.txt | 2 +- plugins/woocommerce-blocks/storybook/main.js | 2 +- .../changelog/50737-fix-37502-inline-doc-typos-in-woo-blocks | 4 ++++ 17 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 plugins/woocommerce/changelog/50737-fix-37502-inline-doc-typos-in-woo-blocks diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.tsx index 63bdef4842a..8296928e1a3 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.tsx @@ -118,7 +118,7 @@ export const Block = ( props: Props ): JSX.Element | null => { }; export default ( props: Props ) => { - // It is necessary because this block has to support serveral contexts: + // It is necessary because this block has to support several contexts: // - Inside `All Products Block` -> `withProductDataContext` HOC // - Inside `Products Block` -> Gutenberg Context // - Inside `Single Product Template` -> Gutenberg Context diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/edit.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/edit.tsx index 17032101036..fcc09be82ee 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/edit.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/edit.tsx @@ -60,7 +60,7 @@ const Edit = ( {
{ * arguments. * * @param {Function} hookTested The hook being tested to use in the - * test comopnent. + * test component. * @param {Array} propKeysForArgs An array of keys for the props that * will be used on the test component that * will have values fed to the tested diff --git a/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.tsx index 8ec946a1970..8db3adcf3a3 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.tsx @@ -212,7 +212,7 @@ const ActiveFiltersBlock = ( { ] ); /** - * Parse the filter URL to set the active rating fitlers. + * Parse the filter URL to set the active rating filters. * This code should be moved to Rating Filter block once it's implemented. */ useEffect( () => { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/hacks.ts b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/hacks.ts index e541ffe9cf9..253d7b46c22 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/hacks.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/hacks.ts @@ -142,7 +142,7 @@ const useLockedChildren = ( { const clientId = targetNode.dataset.block; const isLocked = isBlockLocked( clientId ); - // Prevent the keyboard event from propogating if it supports locking. + // Prevent the keyboard event from propagating if it supports locking. if ( isLocked ) { event.preventDefault(); event.stopPropagation(); diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts index 0f039081dfa..4c77250338a 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts @@ -63,7 +63,7 @@ export const __internalSetRedirectUrl = ( redirectUrl: string ) => ( { /** * Set whether the checkout has an error or not * - * @param hasError Wether the checkout has an error or not + * @param hasError Whether the checkout has an error or not */ export const __internalSetHasError = ( hasError = true ) => ( { type: types.SET_HAS_ERROR, diff --git a/plugins/woocommerce-blocks/assets/js/editor-components/search-list-control/test/hierarchy.js b/plugins/woocommerce-blocks/assets/js/editor-components/search-list-control/test/hierarchy.js index e4fb1def8a2..018723a06c7 100644 --- a/plugins/woocommerce-blocks/assets/js/editor-components/search-list-control/test/hierarchy.js +++ b/plugins/woocommerce-blocks/assets/js/editor-components/search-list-control/test/hierarchy.js @@ -153,7 +153,7 @@ describe( 'buildTermsTree', () => { ] ); } ); - test( 'should return a tree of items, with orphan categories appended to the end, with children of thier own', () => { + test( 'should return a tree of items, with orphan categories appended to the end, with children of their own', () => { const filteredList = [ { id: 1, name: 'Apricots', parent: 0 }, { id: 3, name: 'Elderberry', parent: 2 }, diff --git a/plugins/woocommerce-blocks/assets/js/interactivity/vdom.js b/plugins/woocommerce-blocks/assets/js/interactivity/vdom.js index f399d658a47..7934a73f860 100644 --- a/plugins/woocommerce-blocks/assets/js/interactivity/vdom.js +++ b/plugins/woocommerce-blocks/assets/js/interactivity/vdom.js @@ -21,7 +21,7 @@ const directiveParser = new RegExp( // segments. It excludes underscore intentionally to prevent confusion. // E.g., "custom-directive". '([a-z0-9]+(?:-[a-z0-9]+)*)' + - // (Optional) Match '--' followed by any alphanumeric charachters. It + // (Optional) Match '--' followed by any alphanumeric characters. It // excludes underscore intentionally to prevent confusion, but it can // contain multiple hyphens. E.g., "--custom-prefix--with-more-info". '(?:--([a-z0-9_-]+))?$', diff --git a/plugins/woocommerce-blocks/bin/gen-block-list-doc.js b/plugins/woocommerce-blocks/bin/gen-block-list-doc.js index a4283e99328..3fb13fbec01 100644 --- a/plugins/woocommerce-blocks/bin/gen-block-list-doc.js +++ b/plugins/woocommerce-blocks/bin/gen-block-list-doc.js @@ -103,12 +103,12 @@ function processObjWithInnerKeys( obj ) { * not disabled. So adding { color: 'link' } support also brings along * background and text. * - * @param {Object} supports - keys supported by blokc + * @param {Object} supports - keys supported by block * @return {Object} supports augmented with defaults */ function augmentSupports( supports ) { if ( supports && 'color' in supports ) { - // If backgroud or text is not specified (true or false) + // If background or text is not specified (true or false) // then add it as true.a if ( typeof supports.color === 'object' && diff --git a/plugins/woocommerce-blocks/phpcs.xml b/plugins/woocommerce-blocks/phpcs.xml index 51ada14dae7..9369e670336 100644 --- a/plugins/woocommerce-blocks/phpcs.xml +++ b/plugins/woocommerce-blocks/phpcs.xml @@ -9,7 +9,7 @@ diff --git a/plugins/woocommerce-blocks/readme.txt b/plugins/woocommerce-blocks/readme.txt index bf4f237bcf8..951a43ab579 100644 --- a/plugins/woocommerce-blocks/readme.txt +++ b/plugins/woocommerce-blocks/readme.txt @@ -2723,7 +2723,7 @@ This release fixes an error that some users experienced when their site automati - Fix - Ensure empty categories are correctly hidden in the product categories block. ([3765](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3765)) - Fix - Added missing wrapper div within FeaturedCategory and FeatureProduct blocks. ([3746](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3746)) -- Fix - Set correct text color in BlockErrorBoundry notices. ([3738](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3738)) +- Fix - Set correct text color in BlockErrorBoundary notices. ([3738](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3738)) - Hidden cart item meta data will not be rendered in the Cart and Checkout blocks. ([3732](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3732)) - Fix - Improved accessibility of product image links in the products block by using correct aria tags and hiding empty image placeholders. ([3722](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3722)) - Add missing aria-label for stars image in the review-list-item component. ([3706](https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3706)) diff --git a/plugins/woocommerce-blocks/storybook/main.js b/plugins/woocommerce-blocks/storybook/main.js index a1f07ef3e8a..4a16e281158 100644 --- a/plugins/woocommerce-blocks/storybook/main.js +++ b/plugins/woocommerce-blocks/storybook/main.js @@ -35,7 +35,7 @@ module.exports = { }, // webpackFinal field was added in following PR: https://github.com/woocommerce/woocommerce-blocks/pull/7514 // This fixes "storybook build issue" related to framer-motion library. - // Solution is from this commment: https://github.com/storybookjs/storybook/issues/16690#issuecomment-971579785 + // Solution is from this comment: https://github.com/storybookjs/storybook/issues/16690#issuecomment-971579785 webpackFinal: async ( config ) => { config.module.rules.push( { test: /\.mjs$/, diff --git a/plugins/woocommerce/changelog/50737-fix-37502-inline-doc-typos-in-woo-blocks b/plugins/woocommerce/changelog/50737-fix-37502-inline-doc-typos-in-woo-blocks new file mode 100644 index 00000000000..797c128d011 --- /dev/null +++ b/plugins/woocommerce/changelog/50737-fix-37502-inline-doc-typos-in-woo-blocks @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak +Comment: Fix inline documentation typos in woocommerce-blocks. + From cd54a09c278ea711aa9a016dfaa5b132affe2d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Thomas?= Date: Mon, 19 Aug 2024 16:13:46 +0200 Subject: [PATCH 003/185] Add Tests to Product Reviews (#50060) Co-authored-by: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com> --- .../changelog/e2e-add-tests-prod-reviews | 4 + .../tests/merchant/product-reviews.spec.js | 96 ++++++++++++++++--- 2 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 plugins/woocommerce/changelog/e2e-add-tests-prod-reviews diff --git a/plugins/woocommerce/changelog/e2e-add-tests-prod-reviews b/plugins/woocommerce/changelog/e2e-add-tests-prod-reviews new file mode 100644 index 00000000000..73a2f163215 --- /dev/null +++ b/plugins/woocommerce/changelog/e2e-add-tests-prod-reviews @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +E2E tests for verifying approve, spam and reply to product reviews. diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-reviews.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-reviews.spec.js index 3c0359693c5..8b024315391 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-reviews.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-reviews.spec.js @@ -48,7 +48,7 @@ const test = baseTest.extend( { } ); test.describe( - 'Product Reviews > Edit Product Review', + 'Product Reviews', { tag: [ '@gutenberg', '@services' ] }, () => { test( 'can view products reviews list', async ( { page, reviews } ) => { @@ -77,6 +77,8 @@ test.describe( .first() ).toContainText( review.product_name ); } + + expect( reviews.length ).toBeGreaterThan( 0 ); } ); test( 'can filter the reviews by product', async ( { @@ -139,7 +141,6 @@ test.describe( .getByRole( 'button', { name: 'Update Comment' } ) .click(); - // Verify that the edited comment is there await expect( reviewRow.getByText( updatedQuickReview ) ).toBeVisible(); @@ -148,20 +149,17 @@ test.describe( test( 'can edit a product review', async ( { page, reviews } ) => { const review = reviews[ 0 ]; - // Go to the Edit page of the review await page.goto( `wp-admin/comment.php?action=editcomment&c=${ review.id }` ); await expect( page.getByText( 'Edit Comment' ) ).toBeVisible(); - // Create new comment and edit the review with it const updatedReview = `(edited ${ Date.now() })`; await page .locator( '.wp-editor-area' ) .first() .fill( updatedReview ); - // Generate another random rating and edit the review with it await page.click( '#rating' ); const updatedRating = ( Math.random() * ( 5 - 1 ) + 1 ).toFixed( 0 @@ -171,7 +169,6 @@ test.describe( } ); await page.getByRole( 'button', { name: 'Update' } ).click(); - // Verify that the edited comment is in the product reviews list await page.goto( `wp-admin/edit.php?post_type=product&page=product-reviews` ); @@ -185,7 +182,6 @@ test.describe( reviewRow.getByLabel( `${ updatedRating } out of 5` ) ).toBeVisible(); - // Verify that the edited comment is in the shop's product page await reviewRow.locator( 'a.comments-view-item-link' ).click(); await page.click( '#tab-reviews' ); await expect( @@ -196,7 +192,31 @@ test.describe( ).toBeVisible(); } ); - test( 'can delete a product review', async ( { page, reviews } ) => { + test( 'can approve a product review', async ( { page, reviews } ) => { + const review = reviews[ 0 ]; // Select the first review for approval + + await page.goto( + `wp-admin/edit.php?post_type=product&page=product-reviews` + ); + + const reviewRow = page.locator( `#comment-${ review.id }` ); + + const approveButton = reviewRow.getByRole( 'button', { + name: 'Approve', + } ); + + await reviewRow.hover(); + await approveButton.click(); + const unapproveButton = reviewRow.getByRole( 'button', { + name: 'Unapprove', + } ); + await expect( unapproveButton ).toBeVisible(); + } ); + + test( 'can mark a product review as spam', async ( { + page, + reviews, + } ) => { const review = reviews[ 0 ]; await page.goto( @@ -206,7 +226,59 @@ test.describe( const reviewRow = page.locator( `#comment-${ review.id }` ); await reviewRow.hover(); - // Select Trash action, check confirmation prompt and undo + await reviewRow.getByRole( 'button', { name: 'Spam' } ).click(); + + await expect( + page.locator( `#comment-${ review.id }` ) + ).toBeHidden(); + + await page.click( 'a[href*="comment_status=spam"]' ); + + await expect( + page.locator( `#comment-${ review.id }` ) + ).toBeVisible(); + } ); + + test( 'can reply to a product review', async ( { page, reviews } ) => { + const review = reviews[ 0 ]; + + await page.goto( + 'wp-admin/edit.php?post_type=product&page=product-reviews' + ); + + const reviewRow = page.locator( `#comment-${ review.id }` ); + await reviewRow.hover(); + await reviewRow.getByRole( 'button', { name: 'Reply' } ).click(); + const replyTextArea = page.locator( 'textarea#replycontent' ); + + await expect( replyTextArea ).toBeVisible(); + + const replyText = `Thank you for your feedback! (replied ${ Date.now() })`; + await replyTextArea.fill( replyText ); + + await page.locator( 'button.save.button.button-primary' ).click(); + + const productLink = await reviewRow + .locator( 'a.comments-view-item-link' ) + .getAttribute( 'href' ); + await page.goto( productLink ); + await page.click( '#tab-reviews' ); + + const replyReviews = page.locator( + `div.comment_container:has-text("${ replyText }")` + ); + await expect( replyReviews ).toBeVisible(); + } ); + + test( 'can delete a product review', async ( { page, reviews } ) => { + const review = reviews[ 0 ]; + + await page.goto( + `wp-admin/edit.php?post_type=product&page=product-reviews` + ); + const reviewRow = page.locator( `#comment-${ review.id }` ); + await reviewRow.hover(); + await reviewRow.getByRole( 'button', { name: 'Trash' } ).click(); await expect( page.getByText( @@ -215,26 +287,24 @@ test.describe( ).toBeVisible(); await page.getByRole( 'button', { name: 'Undo' } ).click(); - // Verify that the review has been restored await expect( reviewRow.getByRole( 'cell', { name: review.review } ) ).toBeVisible(); - // Select Trash action and delete it permanently await reviewRow.getByRole( 'button', { name: 'Trash' } ).click(); + await expect( page.getByText( `Comment by ${ review.reviewer } moved to the Trash` ) ).toBeVisible(); - // Verify that the review in the trash await page.click( 'a[href*="comment_status=trash"]' ); + await expect( reviewRow.getByRole( 'cell', { name: review.review } ) ).toBeVisible(); - // Check that the review is in the trash via URL await page.goto( `wp-admin/comment.php?action=editcomment&c=${ review.id }` ); From 99d8b9bf42a0a949cf65228ed377e277cc945d98 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:17:13 -0300 Subject: [PATCH 004/185] Delete changelog files based on PR 50700 (#50712) * Delete changelog files for 50700 * Remove related changelog file --------- Co-authored-by: WooCommerce Bot Co-authored-by: Jorge Torres --- .../changelog/50720-fix-missing-logout-confirmation | 4 ---- .../changelog/fix-set-new-password-regression-49670 | 4 ---- 2 files changed, 8 deletions(-) delete mode 100644 plugins/woocommerce/changelog/50720-fix-missing-logout-confirmation delete mode 100644 plugins/woocommerce/changelog/fix-set-new-password-regression-49670 diff --git a/plugins/woocommerce/changelog/50720-fix-missing-logout-confirmation b/plugins/woocommerce/changelog/50720-fix-missing-logout-confirmation deleted file mode 100644 index 6dc236fbc97..00000000000 --- a/plugins/woocommerce/changelog/50720-fix-missing-logout-confirmation +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: tweak -Comment: Fixes missing global in unreleased code. - diff --git a/plugins/woocommerce/changelog/fix-set-new-password-regression-49670 b/plugins/woocommerce/changelog/fix-set-new-password-regression-49670 deleted file mode 100644 index 5d5e3d5f4dc..00000000000 --- a/plugins/woocommerce/changelog/fix-set-new-password-regression-49670 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fix - -Allow new accounts to set new password even if logged in. From 6b36b42f47bbcf187afb324976c547dc3c23627b Mon Sep 17 00:00:00 2001 From: Seghir Nadir Date: Mon, 19 Aug 2024 18:05:19 +0200 Subject: [PATCH 005/185] Add email type to email field in Checkout block (#48611) * add email type to email field in Checkout block * Add changefile(s) from automation for the following project(s): woocommerce * fix changelog --------- Co-authored-by: github-actions --- plugins/woocommerce/changelog/add-type-to-email-field | 4 ++++ .../woocommerce/src/Blocks/Domain/Services/CheckoutFields.php | 1 + 2 files changed, 5 insertions(+) create mode 100644 plugins/woocommerce/changelog/add-type-to-email-field diff --git a/plugins/woocommerce/changelog/add-type-to-email-field b/plugins/woocommerce/changelog/add-type-to-email-field new file mode 100644 index 00000000000..cec5da4722d --- /dev/null +++ b/plugins/woocommerce/changelog/add-type-to-email-field @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Add email type to Checkout block email field. diff --git a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php index ab9e4c19279..dcf2e0351f8 100644 --- a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php +++ b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php @@ -508,6 +508,7 @@ class CheckoutFields { 'hidden' => false, 'autocomplete' => 'email', 'autocapitalize' => 'none', + 'type' => 'email', 'index' => 0, ], 'country' => [ From 42e943dc0e14620cb0b66b07ab98a85c904fedee Mon Sep 17 00:00:00 2001 From: Matt Sherman Date: Mon, 19 Aug 2024 12:07:11 -0400 Subject: [PATCH 006/185] Decode HTML entities and strip HTML tags in product names for cart quantity change notifications (#50541) * Decode cart item names * Strip HTML tags from product name --------- Co-authored-by: Seghir Nadir --- .../js/data/cart/notify-quantity-changes.ts | 16 +++++++++++----- ...ix-cart-notify-quantity-changes-html-entities | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-cart-notify-quantity-changes-html-entities diff --git a/plugins/woocommerce-blocks/assets/js/data/cart/notify-quantity-changes.ts b/plugins/woocommerce-blocks/assets/js/data/cart/notify-quantity-changes.ts index ad7faeea2fa..44910bf4bb8 100644 --- a/plugins/woocommerce-blocks/assets/js/data/cart/notify-quantity-changes.ts +++ b/plugins/woocommerce-blocks/assets/js/data/cart/notify-quantity-changes.ts @@ -3,7 +3,10 @@ */ import { Cart, CartItem } from '@woocommerce/types'; import { dispatch, select } from '@wordpress/data'; +import { decodeEntities } from '@wordpress/html-entities'; import { __, sprintf } from '@wordpress/i18n'; +// eslint-disable-next-line @wordpress/no-unsafe-wp-apis, @woocommerce/dependency-group +import { __unstableStripHTML as stripHTML } from '@wordpress/dom'; /** * Internal dependencies @@ -25,6 +28,9 @@ const isWithinQuantityLimits = ( cartItem: CartItem ) => { ); }; +const stripAndDecode = ( text: string ) => { + return stripHTML( decodeEntities( text ) ); +}; const notifyIfQuantityLimitsChanged = ( oldCart: Cart, newCart: Cart ) => { newCart.items.forEach( ( cartItem ) => { const oldCartItem = oldCart.items.find( ( item ) => { @@ -64,7 +70,7 @@ const notifyIfQuantityLimitsChanged = ( oldCart: Cart, newCart: Cart ) => { 'The quantity of "%1$s" was changed to %2$d. You must purchase this product in groups of %3$d.', 'woocommerce' ), - cartItem.name, + stripAndDecode( cartItem.name ), // We round down to the nearest step value here. We need to do it this way because at this point we // don't know the next quantity. That only gets set once the HTML Input field applies its min/max // constraints. @@ -91,7 +97,7 @@ const notifyIfQuantityLimitsChanged = ( oldCart: Cart, newCart: Cart ) => { 'The quantity of "%1$s" was increased to %2$d. This is the minimum required quantity.', 'woocommerce' ), - cartItem.name, + stripAndDecode( cartItem.name ), cartItem.quantity_limits.minimum ), { @@ -112,7 +118,7 @@ const notifyIfQuantityLimitsChanged = ( oldCart: Cart, newCart: Cart ) => { 'The quantity of "%1$s" was decreased to %2$d. This is the maximum allowed quantity.', 'woocommerce' ), - cartItem.name, + stripAndDecode( cartItem.name ), cartItem.quantity_limits.maximum ), { @@ -153,7 +159,7 @@ const notifyIfQuantityChanged = ( 'The quantity of "%1$s" was changed to %2$d.', 'woocommerce' ), - cartItem.name, + stripAndDecode( cartItem.name ), cartItem.quantity ), { @@ -195,7 +201,7 @@ const notifyIfRemoved = ( sprintf( /* translators: %s is the name of the item. */ __( '"%s" was removed from your cart.', 'woocommerce' ), - oldCartItem.name + stripAndDecode( oldCartItem.name ) ), { context: 'wc/cart', diff --git a/plugins/woocommerce/changelog/fix-cart-notify-quantity-changes-html-entities b/plugins/woocommerce/changelog/fix-cart-notify-quantity-changes-html-entities new file mode 100644 index 00000000000..768e74c0de3 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-cart-notify-quantity-changes-html-entities @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Cart block: Strip HTML tags and decode HTML entities in quantity change notifications. From cda0f8a3f8caa291c4cf76933121719efc703c73 Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Mon, 19 Aug 2024 18:54:58 +0100 Subject: [PATCH 007/185] Revert "Add new buttonAttributes API to style express checkout buttons coherently (#47899) (#50763) * Revert "Add new buttonAttributes API to style express checkout buttons coherently (#47899)" This reverts commit 006fbc6714d3235ef5f62986a5d1c3d0d4f16fe4. * Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce * Update changelog * Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce --------- Co-authored-by: github-actions --- .../payment-method-integration.md | 56 ++---- docs/docs-manifest.json | 6 +- ...methods.tsx => express-payment-methods.js} | 36 +--- ...ayment.tsx => checkout-express-payment.js} | 0 .../payment-methods/express-payment/index.js | 2 +- .../express-payment/style.scss | 3 +- .../test/__mocks__/editor-context.ts | 3 - .../test/__mocks__/express-payment-props.ts | 188 ------------------ .../test/express-payment-methods.tsx | 122 ------------ .../cart-express-payment-block/editor.scss | 17 -- .../assets/js/blocks/checkout/block.tsx | 2 - .../assets/js/blocks/checkout/context.ts | 2 - .../checkout-express-payment-block/block.json | 12 -- .../checkout-express-payment-block/block.tsx | 1 + .../context.tsx | 21 -- .../checkout-express-payment-block/edit.tsx | 105 +--------- .../editor.scss | 34 ---- .../frontend.tsx | 32 --- .../checkout-express-payment-block/types.ts | 10 - .../inner-blocks/register-components.ts | 2 +- ...899-try-poc-express-checkout-button-styles | 4 - ...evert-47899-express-checkout-button-styles | 4 + 22 files changed, 35 insertions(+), 627 deletions(-) rename plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/{express-payment-methods.tsx => express-payment-methods.js} (81%) rename plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/express-payment/{checkout-express-payment.tsx => checkout-express-payment.js} (100%) delete mode 100644 plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/test/__mocks__/editor-context.ts delete mode 100644 plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/test/__mocks__/express-payment-props.ts delete mode 100644 plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/test/express-payment-methods.tsx delete mode 100644 plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/context.tsx delete mode 100644 plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/frontend.tsx delete mode 100644 plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-express-payment-block/types.ts delete mode 100644 plugins/woocommerce/changelog/47899-try-poc-express-checkout-button-styles create mode 100644 plugins/woocommerce/changelog/50763-revert-47899-express-checkout-button-styles diff --git a/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md b/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md index c7daa61ac23..602bcb7deaa 100644 --- a/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md +++ b/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md @@ -139,24 +139,23 @@ The options you feed the configuration instance are the same as those for expres A big part of the payment method integration is the interface that is exposed for payment methods to use via props when the node provided is cloned and rendered on block mount. While all the props are listed below, you can find more details about what the props reference, their types etc via the [typedefs described in this file](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/types/type-defs/payment-method-interface.ts). -| Property | Type | Description | Values | -| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `activePaymentMethod` | String | The slug of the current active payment method in the checkout. | - | -| `billing` | Object | Contains everything related to billing. | `billingAddress`, `cartTotal`, `currency`, `cartTotalItems`, `displayPricesIncludingTax`, `appliedCoupons`, `customerId` | -| `cartData` | Object | Data exposed from the cart including items, fees, and any registered extension data. Note that this data should be treated as immutable (should not be modified/mutated) or it will result in errors in your application. | `cartItems`, `cartFees`, `extensions` | -| `checkoutStatus` | Object | The current checkout status exposed as various boolean state. | `isCalculating`, `isComplete`, `isIdle`, `isProcessing` | +| Property | Type | Description | Values | +| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `activePaymentMethod` | String | The slug of the current active payment method in the checkout. | - | +| `billing` | Object | Contains everything related to billing. | `billingAddress`, `cartTotal`, `currency`, `cartTotalItems`, `displayPricesIncludingTax`, `appliedCoupons`, `customerId` | +| `cartData` | Object | Data exposed from the cart including items, fees, and any registered extension data. Note that this data should be treated as immutable (should not be modified/mutated) or it will result in errors in your application. | `cartItems`, `cartFees`, `extensions` | +| `checkoutStatus` | Object | The current checkout status exposed as various boolean state. | `isCalculating`, `isComplete`, `isIdle`, `isProcessing` | | `components` | Object | It exposes React components that can be implemented by your payment method for various common interface elements used by payment methods. |
  • `ValidationInputError`: a container for holding validation errors which typically you'll include after any inputs.
  • [`PaymentMethodLabel`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e089ae17043fa525e8397d605f0f470959f2ae95/assets/js/payment-method-extensions/payment-methods/paypal/index.js#L37-L40): use this component for the payment method label, including an optional icon.
  • `PaymentMethodIcons`: a React component used for displaying payment method icons.
  • - `LoadingMask`: a wrapper component that handles displaying a loading state when the isLoading prop is true. Exposes the [LoadingMask component](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c9074a4941919987dbad16a80f358b960336a09d/assets/js/base/components/loading-mask/index.js)
| | `emitResponse` | Object | Contains some constants that can be helpful when using the event emitter. Read the _[Emitting Events](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e267cd96a4329a4eeef816b2ef627e113ebb72a5/docs/extensibility/checkout-flow-and-events.md#emitting-events)_ section for more details. |
  • `noticeContexts`: This is an object containing properties referencing areas where notices can be targeted in the checkout. The object has the following properties:
    • `PAYMENTS`: This is a reference to the notice area in the payment methods step.
    • `EXPRESS_PAYMENTS`: This is a reference to the notice area in the express payment methods step.
  • `responseTypes`: This is an object containing properties referencing the various response types that can be returned by observers for some event emitters. It makes it easier for autocompleting the types and avoiding typos due to human error. The types are `SUCCESS`, `FAIL`, `ERROR`. The values for these types also correspond to the [payment status types](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/Payments/PaymentResult.php#L21) from the [checkout endpoint response from the server](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/RestApi/StoreApi/Schemas/CheckoutSchema.php#L103-L113).
| -| `eventRegistration` | object | Contains all the checkout event emitter registration functions. These are functions the payment method can register observers on to interact with various points in the checkout flow (see [this doc](./checkout-flow-and-events.md) for more info). | `onCheckoutValidation`, `onCheckoutSuccess`, `onCheckoutFail`, `onPaymentSetup`, `onShippingRateSuccess`, `onShippingRateFail`, `onShippingRateSelectSuccess`, `onShippingRateSelectFail` | -| `onClick` | Function | **Provided to express payment methods** that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing) | - | -| `onClose` | Function | **Provided to express payment methods** that should be triggered when the express payment method modal closes and control is returned to checkout. | - | -| `onSubmit` | Function | Submits the checkout and begins processing | - | -| `buttonAttributes` | Object | Styles set by the merchant that should be respected by all express payment buttons | `height, borderRadius, darkMode` | -| `paymentStatus` | Object | Various payment status helpers. Note, your payment method does not have to handle setting this status client side. Checkout will handle this via the responses your payment method gives from observers registered to [checkout event emitters](./checkout-flow-and-events.md). | `isPristine`, `isStarted`, `isProcessing`, `isFinished`, `hasError`, `hasFailed`, `isSuccessful`(see below for explanation) | -| `setExpressPaymentError` | Function | Receives a string and allows express payment methods to set an error notice for the express payment area on demand. This can be necessary because some express payment method processing might happen outside of checkout events. | - | -| `shippingData` | Object | Contains all shipping related data (outside of the shipping status). | `shippingRates`, `shippingRatesLoading`, `selectedRates`, `setSelectedRates`, `isSelectingRate`, `shippingAddress`, `setShippingAddress`, and `needsShipping` | +| `eventRegistration` | object | Contains all the checkout event emitter registration functions. These are functions the payment method can register observers on to interact with various points in the checkout flow (see [this doc](./checkout-flow-and-events.md) for more info). | `onCheckoutValidation`, `onCheckoutSuccess`, `onCheckoutFail`, `onPaymentSetup`, `onShippingRateSuccess`, `onShippingRateFail`, `onShippingRateSelectSuccess`, `onShippingRateSelectFail` | +| `onClick` | Function | **Provided to express payment methods** that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing) | - | +| `onClose` | Function | **Provided to express payment methods** that should be triggered when the express payment method modal closes and control is returned to checkout. | - | +| `onSubmit` | Function | Submits the checkout and begins processing | - | +| `paymentStatus` | Object | Various payment status helpers. Note, your payment method does not have to handle setting this status client side. Checkout will handle this via the responses your payment method gives from observers registered to [checkout event emitters](./checkout-flow-and-events.md). | `isPristine`, `isStarted`, `isProcessing`, `isFinished`, `hasError`, `hasFailed`, `isSuccessful` (see below for explanation) | +| `setExpressPaymentError` | Function | Receives a string and allows express payment methods to set an error notice for the express payment area on demand. This can be necessary because some express payment method processing might happen outside of checkout events. | - | +| `shippingData` | Object | Contains all shipping related data (outside of the shipping status). | `shippingRates`, `shippingRatesLoading`, `selectedRates`, `setSelectedRates`, `isSelectingRate`, `shippingAddress`, `setShippingAddress`, and `needsShipping` | | `shippingStatus` | Object | Various shipping status helpers. |
  • `shippingErrorStatus`: an object with various error statuses that might exist for shipping
  • `shippingErrorTypes`: an object containing all the possible types for shipping error status
| -| `shouldSavePayment` | Boolean | Indicates whether or not the shopper has selected to save their payment method details (for payment methods that support saved payments). True if selected, false otherwise. Defaults to false. | - | +| `shouldSavePayment` | Boolean | Indicates whether or not the shopper has selected to save their payment method details (for payment methods that support saved payments). True if selected, false otherwise. Defaults to false. | - | - `isPristine`: This is true when the current payment status is `PRISTINE`. - `isStarted`: This is true when the current payment status is `EXPRESS_STARTED`. @@ -168,33 +167,6 @@ A big part of the payment method integration is the interface that is exposed fo Any registered `savedTokenComponent` node will also receive a `token` prop which includes the id for the selected saved token in case your payment method needs to use it for some internal logic. However, keep in mind, this is just the id representing this token in the database (and the value of the radio input the shopper checked), not the actual customer payment token (since processing using that usually happens on the server for security). -### Button Attributes for Express Payment Methods - -This API provides a way to synchronise the look and feel of the express payment buttons for a coherent shopper experience. Express Payment Methods must prefer the values provided in the `buttonAttributes`, and use it's own configuration settings as backup when the buttons are rendered somewhere other than the Cart or Checkout block. - -For example, in your button component, you would do something like this: - -```js -// Get your extension specific settings and set defaults if not available -let { - theme = 'dark', - borderRadius = '4', - height = '48', -} = getButtonSettingsFromConfig(); - -// In a cart & checkout block context, we receive `buttonAttributes` as a prop which overwrite the extension specific settings -if ( typeof buttonAttributes !== 'undefined' ) { - height = buttonAttributes.height; - borderRadius = buttonAttributes.borderRadius; - theme = buttonAttributes.darkMode ? 'light' : 'dark'; -} -... - -return + +
+ + ) : null; +}; diff --git a/plugins/woocommerce-admin/client/launch-your-store/settings/components/confirmation-modal.scss b/plugins/woocommerce-admin/client/launch-your-store/settings/components/confirmation-modal.scss new file mode 100644 index 00000000000..be45ad905a6 --- /dev/null +++ b/plugins/woocommerce-admin/client/launch-your-store/settings/components/confirmation-modal.scss @@ -0,0 +1,24 @@ +.site-visibility-settings-confirmation-modal { + .site-visibility-settings-confirmation-modal__content { + margin-top: 15px; + } + + .site-visibility-settings-confirmation-modal__buttons { + display: flex; + flex-flow: row-reverse; + } + + // Hacky solution for a divider line that spans over its container's paddings. + .divider-container { + height: 1px; + margin-bottom: 30px; + margin-top: 25px; + + & > hr { + position: absolute; + width: 100%; + left: 0; + right: 0; + } + } +} diff --git a/plugins/woocommerce-admin/client/launch-your-store/settings/components/test/confirmation-modal.test.js b/plugins/woocommerce-admin/client/launch-your-store/settings/components/test/confirmation-modal.test.js new file mode 100644 index 00000000000..d7267e32cf1 --- /dev/null +++ b/plugins/woocommerce-admin/client/launch-your-store/settings/components/test/confirmation-modal.test.js @@ -0,0 +1,183 @@ +/** + * External dependencies + */ +import React from 'react'; +import { render, fireEvent, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; + +/** + * Internal dependencies + */ +import { ConfirmationModal } from '../confirmation-modal'; + +// Mock the necessary external dependencies +jest.mock( '@wordpress/components', () => ( { + Modal: jest.fn( ( { title, children, onRequestClose } ) => ( +
+
{ title }
+
{ children }
+ +
+ ) ), + Button: jest.fn( ( { children, onClick } ) => ( + + ) ), +} ) ); + +describe( 'ConfirmationModal', () => { + let formRef, saveButtonRef; + + const mockSelectComingSoon = ( value ) => { + // Set up form data + const input = document.createElement( 'input' ); + input.name = 'woocommerce_coming_soon'; + input.value = value; + formRef.current.appendChild( input ); + }; + + const fireSubmitEvent = () => { + // Simulate form submission + const submitEvent = new Event( 'submit', { + bubbles: true, + cancelable: true, + } ); + fireEvent( formRef.current, submitEvent ); + }; + + beforeEach( () => { + formRef = { current: document.createElement( 'form' ) }; + saveButtonRef = { current: document.createElement( 'button' ) }; + formRef.current.appendChild( saveButtonRef.current ); + document.body.appendChild( formRef.current ); + } ); + + afterEach( () => { + document.body.removeChild( formRef.current ); + } ); + + it( 'should prompt the modal if current setting is live and submit the form', () => { + const currentSetting = { woocommerce_coming_soon: 'no' }; + + render( + + ); + + const submitListener = jest.fn(); + formRef.current.onsubmit = submitListener; + + mockSelectComingSoon( 'yes' ); + fireSubmitEvent(); + + // Confirm modal is prompted + expect( + screen.getByText( 'Confirm switch to ‘Coming soon’ mode' ) + ).toBeInTheDocument(); + + // Simulate confirming submission + fireEvent.click( screen.getByText( 'Switch' ) ); + + // Ensure the form is submitted + expect( submitListener ).toHaveBeenCalled(); + } ); + + it( 'should prompt the modal if current setting is not set', () => { + render( + + ); + + mockSelectComingSoon( 'yes' ); + fireSubmitEvent(); + + // Confirm that the modal is not prompted + expect( + screen.queryByText( 'Confirm switch to ‘Coming soon’ mode' ) + ).toBeInTheDocument(); + } ); + + it( 'should not prompt the modal if current setting is already "coming soon"', () => { + const currentSetting = { woocommerce_coming_soon: 'yes' }; + + render( + + ); + + mockSelectComingSoon( 'yes' ); + fireSubmitEvent(); + + // Confirm that the modal is not prompted + expect( + screen.queryByText( 'Confirm switch to ‘Coming soon’ mode' ) + ).not.toBeInTheDocument(); + } ); + + it( 'should close the modal on cancel', () => { + const currentSetting = { woocommerce_coming_soon: 'no' }; + + render( + + ); + + mockSelectComingSoon( 'yes' ); + fireSubmitEvent(); + + // Confirm modal is prompted + expect( + screen.getByText( 'Confirm switch to ‘Coming soon’ mode' ) + ).toBeInTheDocument(); + + // Simulate canceling the modal + fireEvent.click( screen.getByText( 'Cancel' ) ); + + // Confirm that the modal is closed + expect( + screen.queryByText( 'Confirm switch to ‘Coming soon’ mode' ) + ).not.toBeInTheDocument(); + } ); + + it( 'should handle the save button correctly', () => { + const currentSetting = { woocommerce_coming_soon: 'no' }; + saveButtonRef.current.name = 'save'; + saveButtonRef.current.value = 'Save changes'; + + render( + + ); + + mockSelectComingSoon( 'yes' ); + fireSubmitEvent(); + + // Confirm modal is prompted + expect( + screen.getByText( 'Confirm switch to ‘Coming soon’ mode' ) + ).toBeInTheDocument(); + + // Simulate confirming submission + fireEvent.click( screen.getByText( 'Switch' ) ); + + // Check that the hidden input with "save" has been added to the form + const hiddenInput = + formRef.current.querySelector( 'input[name="save"]' ); + expect( hiddenInput ).toBeInTheDocument(); + expect( hiddenInput.value ).toBe( 'Save changes' ); + } ); +} ); diff --git a/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js b/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js index aba9bd41ee6..776579e4101 100644 --- a/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js +++ b/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js @@ -12,6 +12,7 @@ import { createInterpolateElement, createElement, useEffect, + useRef, } from '@wordpress/element'; import { registerPlugin } from '@wordpress/plugins'; import { __ } from '@wordpress/i18n'; @@ -29,6 +30,7 @@ import { COMING_SOON_PAGE_EDITOR_LINK, SITE_VISIBILITY_DOC_LINK, } from '../constants'; +import { ConfirmationModal } from './components/confirmation-modal'; const { Fill } = createSlotFill( SETTINGS_SLOT_FILL_CONSTANT ); @@ -45,6 +47,21 @@ const SiteVisibility = () => { const [ privateLink, setPrivateLink ] = useState( setting?.woocommerce_private_link || 'no' ); + const formRef = useRef( null ); + const saveButtonRef = useRef( null ); + + useEffect( () => { + const saveButton = document.getElementsByClassName( + 'woocommerce-save-button' + )[ 0 ]; + if ( saveButton ) { + saveButtonRef.current = saveButton; + } + const form = document.querySelector( '#mainform' ); + if ( form ) { + formRef.current = form; + } + }, [] ); useEffect( () => { const initValues = { @@ -266,6 +283,13 @@ const SiteVisibility = () => { ) }

+ { formRef.current && saveButtonRef.current ? ( + + ) : null } ); }; diff --git a/plugins/woocommerce/changelog/update-site-visibility-confirmation-modal b/plugins/woocommerce/changelog/update-site-visibility-confirmation-modal new file mode 100644 index 00000000000..341536f2744 --- /dev/null +++ b/plugins/woocommerce/changelog/update-site-visibility-confirmation-modal @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Add confirmation prompt for site visibility settings when changing from live to coming soon mode From 855d94b42d54267afacd28c3c21a5464cef1eb84 Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Tue, 20 Aug 2024 11:46:55 +0800 Subject: [PATCH 014/185] Improve `setup_tasks_remaining()` performance to make `menu_task_count` safer (#50655) * feat: Update TaskLists.php to improve performance and fix bugs The code changes in TaskLists.php optimize the performance by reducing unnecessary checks and improve the functionality by fixing bugs related to the "setup tasks remaining" feature. * Update tests * Add changelog * Fix lint * Update TaskLists.php to fix completed tasks array initialization --- .../changelog/update-improve-setup-task-count | 4 ++ .../Features/OnboardingTasks/TaskLists.php | 28 +++++---- .../features/onboarding-tasks/task-lists.php | 61 ++++++++++++++++++- 3 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 plugins/woocommerce/changelog/update-improve-setup-task-count diff --git a/plugins/woocommerce/changelog/update-improve-setup-task-count b/plugins/woocommerce/changelog/update-improve-setup-task-count new file mode 100644 index 00000000000..98175042ed0 --- /dev/null +++ b/plugins/woocommerce/changelog/update-improve-setup-task-count @@ -0,0 +1,4 @@ +Significance: patch +Type: performance + +Improve setup_tasks_remaining performance diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php index 96fb26f73cd..a60515131c6 100644 --- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php +++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php @@ -297,7 +297,6 @@ class TaskLists { $task_list->add_task( $task ); } } - } /** @@ -318,8 +317,8 @@ class TaskLists { public static function get_lists_by_ids( $ids ) { return array_filter( self::$lists, - function( $list ) use ( $ids ) { - return in_array( $list->get_list_id(), $ids, true ); + function ( $task_list ) use ( $ids ) { + return in_array( $task_list->get_list_id(), $ids, true ); } ); } @@ -404,25 +403,31 @@ class TaskLists { /** * Return number of setup tasks remaining * - * @return number + * This is not updated immediately when a task is completed, but rather when task is marked as complete in the database to reduce performance impact. + * + * @return int|null */ public static function setup_tasks_remaining() { $setup_list = self::get_list( 'setup' ); - if ( ! $setup_list || $setup_list->is_hidden() || $setup_list->has_previously_completed() || $setup_list->is_complete() ) { + if ( ! $setup_list || $setup_list->is_hidden() || $setup_list->has_previously_completed() ) { return; } - $remaining_tasks = array_values( + $viewable_tasks = $setup_list->get_viewable_tasks(); + $completed_tasks = get_option( Task::COMPLETED_OPTION, array() ); + if ( ! is_array( $completed_tasks ) ) { + $completed_tasks = array(); + } + + return count( array_filter( - $setup_list->get_viewable_tasks(), - function( $task ) { - return ! $task->is_complete(); + $viewable_tasks, + function ( $task ) use ( $completed_tasks ) { + return ! in_array( $task->get_id(), $completed_tasks, true ); } ) ); - - return count( $remaining_tasks ); } /** @@ -443,7 +448,6 @@ class TaskLists { break; } } - } /** diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/onboarding-tasks/task-lists.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/onboarding-tasks/task-lists.php index e37548dac5b..175d41d3aab 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/onboarding-tasks/task-lists.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/onboarding-tasks/task-lists.php @@ -10,8 +10,9 @@ */ require_once __DIR__ . '/test-task.php'; -use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskList; use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists; +use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskList; +use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task; /** * Class WC_Tests_OnboardingTasks_TaskLists @@ -42,8 +43,8 @@ class WC_Tests_OnboardingTasks_TaskLists extends WC_Unit_Test_Case { // Filter the default task lists. add_filter( 'woocommerce_admin_experimental_onboarding_tasklists', - function( - $task_lists + function ( + $task_lists ) { $this->assertIsArray( $task_lists ); @@ -138,4 +139,58 @@ class WC_Tests_OnboardingTasks_TaskLists extends WC_Unit_Test_Case { // Assert we have the task we added. $this->assertEquals( 'wc-unit-test_tasklists_get_json_visible_list', $json['tasks'][0]['id'] ); } + + /** + * Tests the setup_tasks_remaining method. + */ + public function test_setup_tasks_remaining() { + // Initialize the default task lists. + TaskLists::add_list( + array( + 'id' => 'setup', + 'title' => 'Setup', + 'tasks' => array(), + 'display_progress_header' => true, + 'event_prefix' => 'tasklist_', + 'options' => array( + 'use_completed_title' => true, + ), + 'visible' => true, + ) + ); + + $setup_list = TaskLists::get_list( 'setup' ); + + for ( $i = 1; $i <= 3; $i++ ) { + TaskLists::add_task( + 'setup', + new TestTask( + $setup_list, + array( + 'id' => "setup-task-{$i}", + ) + ) + ); + } + + // Test when no tasks are completed. + $this->assertEquals( 3, TaskLists::setup_tasks_remaining() ); + + // Complete one task. + update_option( Task::COMPLETED_OPTION, array( 'setup-task-1' ) ); + $this->assertEquals( 2, TaskLists::setup_tasks_remaining() ); + + // Complete all tasks. + update_option( Task::COMPLETED_OPTION, array( 'setup-task-1', 'setup-task-2', 'setup-task-3' ) ); + $this->assertEquals( 0, TaskLists::setup_tasks_remaining() ); + + // Test when the setup list is hidden. + $setup_list->hide(); + $this->assertNull( TaskLists::setup_tasks_remaining() ); + + // Test when the setup list has been previously completed. + $setup_list->unhide(); + update_option( TaskList::COMPLETED_OPTION, array( 'setup' ) ); + $this->assertNull( TaskLists::setup_tasks_remaining() ); + } } From 6a9da3638851de998dbb3f82afb90766f2b546bf Mon Sep 17 00:00:00 2001 From: Moon Date: Mon, 19 Aug 2024 21:29:46 -0700 Subject: [PATCH 015/185] Track product and tax rates importer view triggered from WP importer/exporter (#50769) * Track product and tax rates importer view triggered from WP importer screen * Add changefile(s) from automation for the following project(s): woocommerce * Use $this for the callback * Make sure id exist * Do not track if we are in a specific import screen * Ignore phpcs warning -- we are not using the value --------- Co-authored-by: github-actions --- ...69-add-tracking-to-wp-import-export-screen | 4 ++ .../admin/class-wc-admin-importers.php | 41 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 plugins/woocommerce/changelog/50769-add-tracking-to-wp-import-export-screen diff --git a/plugins/woocommerce/changelog/50769-add-tracking-to-wp-import-export-screen b/plugins/woocommerce/changelog/50769-add-tracking-to-wp-import-export-screen new file mode 100644 index 00000000000..2486a0fff3b --- /dev/null +++ b/plugins/woocommerce/changelog/50769-add-tracking-to-wp-import-export-screen @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add tracks for WordPress Importer/Export pages. \ No newline at end of file diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-importers.php b/plugins/woocommerce/includes/admin/class-wc-admin-importers.php index 37c59e4dc5b..6dfec075b89 100644 --- a/plugins/woocommerce/includes/admin/class-wc-admin-importers.php +++ b/plugins/woocommerce/includes/admin/class-wc-admin-importers.php @@ -1,4 +1,4 @@ -importers['product_importer'] = array( @@ -96,10 +97,15 @@ class WC_Admin_Importers { */ public function product_importer() { if ( Constants::is_defined( 'WP_LOAD_IMPORTERS' ) ) { - wp_safe_redirect( admin_url( 'edit.php?post_type=product&page=product_importer' ) ); + wp_safe_redirect( admin_url( 'edit.php?post_type=product&page=product_importer&source=wordpress-importer' ) ); exit; } + // phpcs:ignore + if ( isset( $_GET['source'] ) && 'wordpress-importer' === sanitize_text_field( wp_unslash( $_GET['source'] ) ) ) { + wc_admin_record_tracks_event( 'product_importer_view_from_wp_importer' ); + } + include_once WC_ABSPATH . 'includes/import/class-wc-product-csv-importer.php'; include_once WC_ABSPATH . 'includes/admin/importers/class-wc-product-csv-importer-controller.php'; @@ -132,7 +138,9 @@ class WC_Admin_Importers { } } - require dirname( __FILE__ ) . '/importers/class-wc-tax-rate-importer.php'; + wc_admin_record_tracks_event( 'tax_rates_importer_view_from_wp_importer' ); + + require __DIR__ . '/importers/class-wc-tax-rate-importer.php'; $importer = new WC_Tax_Rate_Importer(); $importer->dispatch(); @@ -182,7 +190,9 @@ class WC_Admin_Importers { // Register the taxonomy now so that the import works! register_taxonomy( $term['domain'], + // phpcs:ignore apply_filters( 'woocommerce_taxonomy_objects_' . $term['domain'], array( 'product' ) ), + // phpcs:ignore apply_filters( 'woocommerce_taxonomy_args_' . $term['domain'], array( @@ -229,7 +239,7 @@ class WC_Admin_Importers { * * @param int $size Batch size. * - * @since + * @since 3.1.0 */ 'lines' => apply_filters( 'woocommerce_product_import_batch_size', 30 ), 'parse' => true, @@ -314,6 +324,29 @@ class WC_Admin_Importers { ); } } + + /** + * Track importer/exporter view. + * + * @return void + */ + public function track_importer_exporter_view() { + $screen = get_current_screen(); + + if ( ! isset( $screen->id ) ) { + return; + } + + // Don't track if we're in a specific import screen. + // phpcs:ignore + if ( isset( $_GET['import'] ) ) { + return; + } + + if ( 'import' === $screen->id || 'export' === $screen->id ) { + wc_admin_record_tracks_event( 'wordpress_' . $screen->id . '_view' ); + } + } } new WC_Admin_Importers(); From 403d78ae22ff81c4230cea8aeb19a5d831e622e8 Mon Sep 17 00:00:00 2001 From: Akeda Bagus Date: Tue, 20 Aug 2024 11:50:26 +0700 Subject: [PATCH 016/185] Fix wcadmin-product-usage-notice-modal react18 createroot (#50765) --- .../wp-admin-scripts/woo-product-usage-notice/index.js | 7 +++---- .../fix-wcadmin-react18-product-usage-notice-modal | 4 ++++ 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-wcadmin-react18-product-usage-notice-modal diff --git a/plugins/woocommerce-admin/client/wp-admin-scripts/woo-product-usage-notice/index.js b/plugins/woocommerce-admin/client/wp-admin-scripts/woo-product-usage-notice/index.js index dc4e0670e88..ccaab793a41 100644 --- a/plugins/woocommerce-admin/client/wp-admin-scripts/woo-product-usage-notice/index.js +++ b/plugins/woocommerce-admin/client/wp-admin-scripts/woo-product-usage-notice/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { render } from '@wordpress/element'; +import { createRoot } from '@wordpress/element'; /** * Internal dependencies @@ -27,7 +27,7 @@ const { const container = document.createElement( 'div' ); container.setAttribute( 'id', 'woo-product-usage-notice' ); -render( +createRoot( document.body.appendChild( container ) ).render( , - document.body.appendChild( container ) + /> ); diff --git a/plugins/woocommerce/changelog/fix-wcadmin-react18-product-usage-notice-modal b/plugins/woocommerce/changelog/fix-wcadmin-react18-product-usage-notice-modal new file mode 100644 index 00000000000..60ecc7ee16f --- /dev/null +++ b/plugins/woocommerce/changelog/fix-wcadmin-react18-product-usage-notice-modal @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Changed from using React.render to React.createRoot for product-usage-notice-modal as it has been deprecated since React 18 From deaca578cc858cd5e68a079c06c39b1bb77eadfa Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Tue, 20 Aug 2024 13:06:57 +0800 Subject: [PATCH 017/185] Migrate LYS user meta (#50664) * Migrate lys meta * Update lys meta logic * Update user preferences types and logic * Add changelog * Revert changes * Fix types * Fix logic * Fix lint --- .../js/data/changelog/update-lys-tour-meta | 4 + packages/js/data/src/user/types.ts | 9 +- .../js/data/src/user/use-user-preferences.ts | 31 ++--- .../tour/use-site-visibility-tour.tsx | 65 +++++---- .../changelog/update-lys-tour-meta | 4 + .../client/legacy/js/frontend/woocommerce.js | 129 +++++++++++------- .../woocommerce/includes/class-wc-install.php | 1 + .../includes/wc-update-functions.php | 28 ++++ .../src/Admin/Features/LaunchYourStore.php | 33 ++++- 9 files changed, 195 insertions(+), 109 deletions(-) create mode 100644 packages/js/data/changelog/update-lys-tour-meta create mode 100644 plugins/woocommerce/changelog/update-lys-tour-meta diff --git a/packages/js/data/changelog/update-lys-tour-meta b/packages/js/data/changelog/update-lys-tour-meta new file mode 100644 index 00000000000..eec09d7e111 --- /dev/null +++ b/packages/js/data/changelog/update-lys-tour-meta @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Update user preferences types and logic diff --git a/packages/js/data/src/user/types.ts b/packages/js/data/src/user/types.ts index 91b057b7eff..34328a41f18 100644 --- a/packages/js/data/src/user/types.ts +++ b/packages/js/data/src/user/types.ts @@ -33,13 +33,12 @@ export type UserPreferences = { product_advice_card_dismissed?: { [ key: string ]: 'yes' | 'no'; }; + launch_your_store_tour_hidden?: 'yes' | 'no' | ''; + coming_soon_banner_dismissed?: 'yes' | 'no' | ''; }; -export type WoocommerceMeta = UserPreferences & { - task_list_tracked_started_tasks?: string; - variable_items_without_price_notice_dismissed?: string; - local_attributes_notice_dismissed_ids?: string; - product_advice_card_dismissed?: string; +export type WoocommerceMeta = { + [ key in keyof UserPreferences ]: string; }; export type WCUser< diff --git a/packages/js/data/src/user/use-user-preferences.ts b/packages/js/data/src/user/use-user-preferences.ts index e1367d482f0..779cb8adf03 100644 --- a/packages/js/data/src/user/use-user-preferences.ts +++ b/packages/js/data/src/user/use-user-preferences.ts @@ -19,28 +19,15 @@ import { WCUser, UserPreferences } from './types'; const getWooCommerceMeta = ( user: WCUser ) => { const wooMeta = user.woocommerce_meta || {}; - const userData = mapValues( wooMeta, ( data, key ) => { + const userData = mapValues( wooMeta, ( data ) => { if ( ! data || data.length === 0 ) { return ''; } try { return JSON.parse( data ); } catch ( e ) { - if ( e instanceof Error ) { - /* eslint-disable no-console */ - console.error( - `Error parsing value '${ data }' for ${ key }`, - e.message - ); - /* eslint-enable no-console */ - } else { - /* eslint-disable no-console */ - console.error( - `Unexpected Error parsing value '${ data }' for ${ key } ${ e }` - ); - /* eslint-enable no-console */ - } - return ''; + // If we can't parse the value, return the raw data. The meta value could be a string like 'yes' or 'no'. + return data; } } ); @@ -53,7 +40,7 @@ async function updateUserPrefs( user: WCUser, saveUser: ( userToSave: { id: number; - woocommerce_meta: { [ key: string ]: boolean }; + woocommerce_meta: WCUser[ 'woocommerce_meta' ]; } ) => WCUser, getLastEntitySaveError: ( kind: string, @@ -64,7 +51,14 @@ async function updateUserPrefs( ) { // @todo Handle unresolved getCurrentUser() here. // Prep fields for update. - const metaData = mapValues( userPrefs, JSON.stringify ); + const metaData = mapValues( userPrefs, ( value ) => { + if ( typeof value === 'string' ) { + // If the value is a string, we don't need to serialize it. + return value; + } + + return JSON.stringify( value ); + } ); if ( Object.keys( metaData ).length === 0 ) { return { @@ -81,7 +75,6 @@ async function updateUserPrefs( ...metaData, }, } ); - // Use saveUser() to update WooCommerce meta values. const updatedUser = await saveUser( { id: user.id, diff --git a/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx b/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx index 3b6562d254f..4dc98b1ee09 100644 --- a/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx +++ b/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx @@ -1,50 +1,57 @@ /** * External dependencies */ -import { OPTIONS_STORE_NAME } from '@woocommerce/data'; -import { useSelect, dispatch } from '@wordpress/data'; +import { OPTIONS_STORE_NAME, useUserPreferences } from '@woocommerce/data'; +import { useSelect } from '@wordpress/data'; import { useState } from 'react'; -const LYS_TOUR_HIDDEN = 'woocommerce_launch_your_store_tour_hidden'; - export const useSiteVisibilityTour = () => { const [ showTour, setShowTour ] = useState( true ); - const { shouldTourBeShown } = useSelect( ( select ) => { - // Tour should only be shown if the user has not seen it before and the `woocommerce_show_lys_tour` option is "yes" (for sites upgrading from a previous WooCommerce version) - const { getCurrentUser } = select( 'core' ); - const wasTourShown = + // Tour should only be shown if the user has not seen it before and the `woocommerce_show_lys_tour` option is "yes" (for sites upgrading from a previous WooCommerce version) + const shouldStoreShowLYSTour = useSelect( + ( select ) => + select( OPTIONS_STORE_NAME ).getOption( + 'woocommerce_show_lys_tour' + ) === 'yes' + ); + + /** + * This is temporary to support sites upgrading from a previous version of WooCommerce. + * We used user meta to store the tour dismissal state but now we use WooCommerce meta instead. + * It will be removed in WC 9.4. + */ + const hasUserDismissedTourMeta = useSelect( ( select ) => { + const currentUser = select( 'core' ).getCurrentUser(); + if ( ! currentUser ) { + // If the user is not logged in, we don't want to show the tour. + return true; + } + + return ( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - ( getCurrentUser() as { meta?: { [ key: string ]: string } } ) - ?.meta?.[ LYS_TOUR_HIDDEN ] === 'yes'; - - const { getOption } = select( OPTIONS_STORE_NAME ); - - const showLYSTourOption = getOption( 'woocommerce_show_lys_tour' ); - - const _shouldTourBeShown = - showLYSTourOption === 'yes' && ! wasTourShown; - - return { - shouldTourBeShown: _shouldTourBeShown, - }; + ( currentUser as { meta: { [ key: string ]: string } } ).meta + .woocommerce_launch_your_store_tour_hidden === 'yes' + ); } ); + const { + launch_your_store_tour_hidden: lysTourHidden, + updateUserPreferences, + } = useUserPreferences(); + const onClose = () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - dispatch( 'core' ).saveUser( { - id: window?.wcSettings?.currentUserId, - meta: { - woocommerce_launch_your_store_tour_hidden: 'yes', - }, + updateUserPreferences( { + launch_your_store_tour_hidden: 'yes', } ); }; return { onClose, - shouldTourBeShown, + shouldTourBeShown: + shouldStoreShowLYSTour && + ! ( hasUserDismissedTourMeta || lysTourHidden ), showTour, setShowTour, }; diff --git a/plugins/woocommerce/changelog/update-lys-tour-meta b/plugins/woocommerce/changelog/update-lys-tour-meta new file mode 100644 index 00000000000..662915b86e2 --- /dev/null +++ b/plugins/woocommerce/changelog/update-lys-tour-meta @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Migrate LYS user meta diff --git a/plugins/woocommerce/client/legacy/js/frontend/woocommerce.js b/plugins/woocommerce/client/legacy/js/frontend/woocommerce.js index c3190ac687b..10946dc0407 100644 --- a/plugins/woocommerce/client/legacy/js/frontend/woocommerce.js +++ b/plugins/woocommerce/client/legacy/js/frontend/woocommerce.js @@ -1,20 +1,20 @@ /* global Cookies */ -jQuery( function( $ ) { +jQuery( function ( $ ) { // Orderby - $( '.woocommerce-ordering' ).on( 'change', 'select.orderby', function() { + $( '.woocommerce-ordering' ).on( 'change', 'select.orderby', function () { $( this ).closest( 'form' ).trigger( 'submit' ); - }); + } ); // Target quantity inputs on product pages - $( 'input.qty:not(.product-quantity input.qty)' ).each( function() { + $( 'input.qty:not(.product-quantity input.qty)' ).each( function () { var min = parseFloat( $( this ).attr( 'min' ) ); if ( min >= 0 && parseFloat( $( this ).val() ) < min ) { $( this ).val( min ); } - }); + } ); - var noticeID = $( '.woocommerce-store-notice' ).data( 'noticeId' ) || '', + var noticeID = $( '.woocommerce-store-notice' ).data( 'noticeId' ) || '', cookieName = 'store_notice' + noticeID; // Check the value of that cookie and show/hide the notice accordingly @@ -25,43 +25,56 @@ jQuery( function( $ ) { } // Set a cookie and hide the store notice when the dismiss button is clicked - $( '.woocommerce-store-notice__dismiss-link' ).on( 'click', function( event ) { - Cookies.set( cookieName, 'hidden', { path: '/' } ); - $( '.woocommerce-store-notice' ).hide(); - event.preventDefault(); - }); + $( '.woocommerce-store-notice__dismiss-link' ).on( + 'click', + function ( event ) { + Cookies.set( cookieName, 'hidden', { path: '/' } ); + $( '.woocommerce-store-notice' ).hide(); + event.preventDefault(); + } + ); // Make form field descriptions toggle on focus. if ( $( '.woocommerce-input-wrapper span.description' ).length ) { - $( document.body ).on( 'click', function() { - $( '.woocommerce-input-wrapper span.description:visible' ).prop( 'aria-hidden', true ).slideUp( 250 ); + $( document.body ).on( 'click', function () { + $( '.woocommerce-input-wrapper span.description:visible' ) + .prop( 'aria-hidden', true ) + .slideUp( 250 ); } ); } - $( '.woocommerce-input-wrapper' ).on( 'click', function( event ) { + $( '.woocommerce-input-wrapper' ).on( 'click', function ( event ) { event.stopPropagation(); } ); $( '.woocommerce-input-wrapper :input' ) - .on( 'keydown', function( event ) { - var input = $( this ), - parent = input.parent(), + .on( 'keydown', function ( event ) { + var input = $( this ), + parent = input.parent(), description = parent.find( 'span.description' ); - if ( 27 === event.which && description.length && description.is( ':visible' ) ) { + if ( + 27 === event.which && + description.length && + description.is( ':visible' ) + ) { description.prop( 'aria-hidden', true ).slideUp( 250 ); event.preventDefault(); return false; } } ) - .on( 'click focus', function() { - var input = $( this ), - parent = input.parent(), + .on( 'click focus', function () { + var input = $( this ), + parent = input.parent(), description = parent.find( 'span.description' ); parent.addClass( 'currentTarget' ); - $( '.woocommerce-input-wrapper:not(.currentTarget) span.description:visible' ).prop( 'aria-hidden', true ).slideUp( 250 ); + $( + '.woocommerce-input-wrapper:not(.currentTarget) span.description:visible' + ) + .prop( 'aria-hidden', true ) + .slideUp( 250 ); if ( description.length && description.is( ':hidden' ) ) { description.prop( 'aria-hidden', false ).slideDown( 250 ); @@ -71,52 +84,66 @@ jQuery( function( $ ) { } ); // Common scroll to element code. - $.scroll_to_notices = function( scrollElement ) { + $.scroll_to_notices = function ( scrollElement ) { if ( scrollElement.length ) { - $( 'html, body' ).animate( { - scrollTop: ( scrollElement.offset().top - 100 ) - }, 1000 ); + $( 'html, body' ).animate( + { + scrollTop: scrollElement.offset().top - 100, + }, + 1000 + ); } }; // Show password visibility hover icon on woocommerce forms - $( '.woocommerce form .woocommerce-Input[type="password"]' ).wrap( '' ); + $( '.woocommerce form .woocommerce-Input[type="password"]' ).wrap( + '' + ); // Add 'password-input' class to the password wrapper in checkout page. - $( '.woocommerce form input' ).filter(':password').parent('span').addClass('password-input'); - $( '.password-input' ).append( '' ); - - $( '.show-password-input' ).on( 'click', - function() { - if ( $( this ).hasClass( 'display-password' ) ) { - $( this ).removeClass( 'display-password' ); - } else { - $( this ).addClass( 'display-password' ); - } - if ( $( this ).hasClass( 'display-password' ) ) { - $( this ).siblings( ['input[type="password"]'] ).prop( 'type', 'text' ); - } else { - $( this ).siblings( 'input[type="text"]' ).prop( 'type', 'password' ); - } - } + $( '.woocommerce form input' ) + .filter( ':password' ) + .parent( 'span' ) + .addClass( 'password-input' ); + $( '.password-input' ).append( + '' ); + $( '.show-password-input' ).on( 'click', function () { + if ( $( this ).hasClass( 'display-password' ) ) { + $( this ).removeClass( 'display-password' ); + } else { + $( this ).addClass( 'display-password' ); + } + if ( $( this ).hasClass( 'display-password' ) ) { + $( this ) + .siblings( [ 'input[type="password"]' ] ) + .prop( 'type', 'text' ); + } else { + $( this ) + .siblings( 'input[type="text"]' ) + .prop( 'type', 'password' ); + } + } ); - $( 'a.coming-soon-footer-banner-dismiss' ).on( 'click', function( e ) { + $( 'a.coming-soon-footer-banner-dismiss' ).on( 'click', function ( e ) { var target = $( e.target ); $.ajax( { type: 'post', url: target.data( 'rest-url' ), data: { - meta: { - 'woocommerce_coming_soon_banner_dismissed': 'yes' - } + woocommerce_meta: { + coming_soon_banner_dismissed: 'yes', + }, }, beforeSend: function ( xhr ) { - xhr.setRequestHeader( 'X-WP-Nonce', target.data( 'rest-nonce' ) ); + xhr.setRequestHeader( + 'X-WP-Nonce', + target.data( 'rest-nonce' ) + ); }, complete: function () { - $('#coming-soon-footer-banner').hide(); - } + $( '#coming-soon-footer-banner' ).hide(); + }, } ); } ); -}); +} ); diff --git a/plugins/woocommerce/includes/class-wc-install.php b/plugins/woocommerce/includes/class-wc-install.php index d5184396673..e6d591d8d11 100644 --- a/plugins/woocommerce/includes/class-wc-install.php +++ b/plugins/woocommerce/includes/class-wc-install.php @@ -264,6 +264,7 @@ class WC_Install { ), '9.3.0' => array( 'wc_update_930_add_woocommerce_coming_soon_option', + 'wc_update_930_migrate_user_meta_for_launch_your_store_tour', ), ); diff --git a/plugins/woocommerce/includes/wc-update-functions.php b/plugins/woocommerce/includes/wc-update-functions.php index 9879e6e5538..6076aa58646 100644 --- a/plugins/woocommerce/includes/wc-update-functions.php +++ b/plugins/woocommerce/includes/wc-update-functions.php @@ -2824,3 +2824,31 @@ function wc_update_910_remove_obsolete_user_meta() { function wc_update_930_add_woocommerce_coming_soon_option() { add_option( 'woocommerce_coming_soon', 'no' ); } + +/** + * Migrate Launch Your Store tour meta keys to the woocommerce_meta user data fields. + */ +function wc_update_930_migrate_user_meta_for_launch_your_store_tour() { + // Rename `woocommerce_launch_your_store_tour_hidden` meta key to `woocommerce_admin_launch_your_store_tour_hidden`. + global $wpdb; + $wpdb->query( + $wpdb->prepare( + "UPDATE {$wpdb->usermeta} + SET meta_key = %s + WHERE meta_key = %s", + 'woocommerce_admin_launch_your_store_tour_hidden', + 'woocommerce_launch_your_store_tour_hidden' + ) + ); + + // Rename `woocommerce_coming_soon_banner_dismissed` meta key to `woocommerce_admin_coming_soon_banner_dismissed`. + $wpdb->query( + $wpdb->prepare( + "UPDATE {$wpdb->usermeta} + SET meta_key = %s + WHERE meta_key = %s", + 'woocommerce_admin_coming_soon_banner_dismissed', + 'woocommerce_coming_soon_banner_dismissed' + ) + ); +} diff --git a/plugins/woocommerce/src/Admin/Features/LaunchYourStore.php b/plugins/woocommerce/src/Admin/Features/LaunchYourStore.php index cc83a73dd15..3bfff4518fe 100644 --- a/plugins/woocommerce/src/Admin/Features/LaunchYourStore.php +++ b/plugins/woocommerce/src/Admin/Features/LaunchYourStore.php @@ -5,12 +5,13 @@ namespace Automattic\WooCommerce\Admin\Features; use Automattic\WooCommerce\Admin\PageController; use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils; use Automattic\WooCommerce\Admin\WCAdminHelper; +use Automattic\WooCommerce\Internal\Admin\WCAdminUser; /** * Takes care of Launch Your Store related actions. */ class LaunchYourStore { - const BANNER_DISMISS_USER_META_KEY = 'woocommerce_coming_soon_banner_dismissed'; + const BANNER_DISMISS_USER_META_KEY = 'coming_soon_banner_dismissed'; /** * Constructor. */ @@ -21,6 +22,7 @@ class LaunchYourStore { add_action( 'init', array( $this, 'register_launch_your_store_user_meta_fields' ) ); add_filter( 'woocommerce_tracks_event_properties', array( $this, 'append_coming_soon_global_tracks' ), 10, 2 ); add_action( 'wp_login', array( $this, 'reset_woocommerce_coming_soon_banner_dismissed' ), 10, 2 ); + add_filter( 'woocommerce_admin_get_user_data_fields', array( $this, 'add_user_data_fields' ) ); } /** @@ -160,7 +162,10 @@ class LaunchYourStore { return false; } - if ( get_user_meta( $current_user_id, self::BANNER_DISMISS_USER_META_KEY, true ) === 'yes' ) { + $has_dismissed_banner = WCAdminUser::get_user_data_field( $current_user_id, self::BANNER_DISMISS_USER_META_KEY ) + // Remove this check in WC 9.4. + || get_user_meta( $current_user_id, 'woocommerce_' . self::BANNER_DISMISS_USER_META_KEY, true ) === 'yes'; + if ( $has_dismissed_banner ) { return false; } @@ -198,6 +203,8 @@ class LaunchYourStore { /** * Register user meta fields for Launch Your Store. + * + * This should be removed in WC 9.4. */ public function register_launch_your_store_user_meta_fields() { if ( ! $this->is_manager_or_admin() ) { @@ -217,7 +224,7 @@ class LaunchYourStore { register_meta( 'user', - self::BANNER_DISMISS_USER_META_KEY, + 'woocommerce_coming_soon_banner_dismissed', array( 'type' => 'string', 'description' => 'Indicate whether the user has dismissed the coming soon notice or not.', @@ -227,6 +234,22 @@ class LaunchYourStore { ); } + /** + * Register user meta fields for Launch Your Store. + * + * @param array $user_data_fields user data fields. + * @return array + */ + public function add_user_data_fields( $user_data_fields ) { + return array_merge( + $user_data_fields, + array( + 'launch_your_store_tour_hidden', + self::BANNER_DISMISS_USER_META_KEY, + ) + ); + } + /** * Reset 'woocommerce_coming_soon_banner_dismissed' user meta to 'no'. * @@ -236,9 +259,9 @@ class LaunchYourStore { * @param object $user user object. */ public function reset_woocommerce_coming_soon_banner_dismissed( $user_login, $user ) { - $existing_meta = get_user_meta( $user->ID, self::BANNER_DISMISS_USER_META_KEY, true ); + $existing_meta = WCAdminUser::get_user_data_field( $user->ID, self::BANNER_DISMISS_USER_META_KEY ); if ( 'yes' === $existing_meta ) { - update_user_meta( $user->ID, self::BANNER_DISMISS_USER_META_KEY, 'no' ); + WCAdminUser::update_user_data_field( $user->ID, self::BANNER_DISMISS_USER_META_KEY, 'no' ); } } } From c7b7805b7ec9928a42c862dafa4949b41186cb37 Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Tue, 20 Aug 2024 13:49:05 +0800 Subject: [PATCH 018/185] Site visibility settings add documentation link and copy changes (#50781) * Add link to title, remove link from a description, minor copy changes * Changelog * Update link * Update test and copies --- .../client/launch-your-store/constants.ts | 2 +- .../launch-your-store/settings/slotfill.js | 31 ++++++++++--------- ...gs-add-documentation-link-and-copy-changes | 4 +++ .../Blueprint/Exporters/ExportWCSettings.php | 2 +- .../ComingSoon/ComingSoonRequestHandler.php | 2 +- .../tests/merchant/launch-your-store.spec.js | 6 ++-- 6 files changed, 27 insertions(+), 20 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-50779-site-visibility-settings-add-documentation-link-and-copy-changes diff --git a/plugins/woocommerce-admin/client/launch-your-store/constants.ts b/plugins/woocommerce-admin/client/launch-your-store/constants.ts index a6a2bbdf15c..9b95ffc736c 100644 --- a/plugins/woocommerce-admin/client/launch-your-store/constants.ts +++ b/plugins/woocommerce-admin/client/launch-your-store/constants.ts @@ -8,7 +8,7 @@ export const COMING_SOON_PAGE_EDITOR_LINK = getAdminLink( ); export const SITE_VISIBILITY_DOC_LINK = - 'https://woocommerce.com/document/woocommerce-launch-your-store/'; + 'https://woocommerce.com/document/configuring-woocommerce-settings/coming-soon-mode/'; export const LAUNCH_YOUR_STORE_DOC_LINK = 'https://woocommerce.com/document/configuring-woocommerce-settings/#site-visibility'; diff --git a/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js b/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js index 776579e4101..370675bc000 100644 --- a/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js +++ b/plugins/woocommerce-admin/client/launch-your-store/settings/slotfill.js @@ -132,9 +132,18 @@ const SiteVisibility = () => { />

{ __( 'Site visibility', 'woocommerce' ) }

- { __( - 'Manage how your site appears to visitors.', - 'woocommerce' + { createInterpolateElement( + __( + 'Manage how your site appears to visitors. Learn more', + 'woocommerce' + ), + { + a: createElement( 'a', { + target: '_blank', + rel: 'noreferrer', + href: SITE_VISIBILITY_DOC_LINK, + } ), + } ) }

@@ -162,6 +171,7 @@ const SiteVisibility = () => { ), { a: createElement( 'a', { + target: '_blank', href: COMING_SOON_PAGE_EDITOR_LINK, } ), } @@ -183,20 +193,13 @@ const SiteVisibility = () => { label={ <> { __( - 'Restrict to store pages only', + 'Apply to store pages only', 'woocommerce' ) }

- { createInterpolateElement( - __( - 'Display a "coming soon" message on your store pages — the rest of your site will remain visible.', - 'woocommerce' - ), - { - a: createElement( 'a', { - href: SITE_VISIBILITY_DOC_LINK, - } ), - } + { __( + 'Display a “coming soon” message on your store pages — the rest of your site will remain visible.', + 'woocommerce' ) }

diff --git a/plugins/woocommerce/changelog/fix-50779-site-visibility-settings-add-documentation-link-and-copy-changes b/plugins/woocommerce/changelog/fix-50779-site-visibility-settings-add-documentation-link-and-copy-changes new file mode 100644 index 00000000000..97462b98589 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50779-site-visibility-settings-add-documentation-link-and-copy-changes @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak + +Add link to title, remove link from a description, minor copy changes to site visibility settings page diff --git a/plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettings.php b/plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettings.php index 1a8ac50c233..97f02b7452e 100644 --- a/plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettings.php +++ b/plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettings.php @@ -198,7 +198,7 @@ class ExportWCSettings implements StepExporter, HasAlias { $option_info['woocommerce_store_pages_only'] = array( 'location' => 'site_visibility.general', - 'title' => 'Restrict to store pages only', + 'title' => 'Apply to store pages only', ); return compact( 'options', 'pages', 'option_info' ); diff --git a/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonRequestHandler.php b/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonRequestHandler.php index f0465b18d0f..d72074780f1 100644 --- a/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonRequestHandler.php +++ b/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonRequestHandler.php @@ -113,7 +113,7 @@ class ComingSoonRequestHandler { return false; } - // Do not show coming soon on 404 pages when restrict to store pages only. + // Do not show coming soon on 404 pages when applied to store pages only. if ( $this->coming_soon_helper->is_store_coming_soon() && is_404() ) { return false; } diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js index b8e778c39db..19f9ce4255c 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js @@ -132,7 +132,7 @@ test.describe( // The store only checkbox should not be on the page. await expect( page.getByRole( 'checkbox', { - name: 'Restrict to store pages only', + name: 'Apply to store pages only', } ) ).toHaveCount( 0 ); @@ -156,14 +156,14 @@ test.describe( // The store only checkbox should be visible. await expect( page.getByRole( 'checkbox', { - name: 'Restrict to store pages only', + name: 'Apply to store pages only', } ) ).toBeVisible(); // The store only checkbox should not be checked. await expect( page.getByRole( 'checkbox', { - name: 'Restrict to store pages only', + name: 'Apply to store pages only', } ) ).not.toBeChecked(); From 34d40f9a637c56a94727329f618e0a34477e0970 Mon Sep 17 00:00:00 2001 From: RJ <27843274+rjchow@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:57:28 +0800 Subject: [PATCH 019/185] dev: see which tests fail when coming soon is enabled (#50344) * test: see which tests fail when coming soon is enabled * changelog * empty commit to trigger CI --- .../woocommerce/changelog/dev-dont-disable-coming-soon-e2e | 4 ++++ plugins/woocommerce/tests/e2e-pw/bin/test-env-setup.sh | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 plugins/woocommerce/changelog/dev-dont-disable-coming-soon-e2e diff --git a/plugins/woocommerce/changelog/dev-dont-disable-coming-soon-e2e b/plugins/woocommerce/changelog/dev-dont-disable-coming-soon-e2e new file mode 100644 index 00000000000..73624bf68e9 --- /dev/null +++ b/plugins/woocommerce/changelog/dev-dont-disable-coming-soon-e2e @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Removed directive to disable woocommerce_coming_soon in e2e tests so that we get better test coverage diff --git a/plugins/woocommerce/tests/e2e-pw/bin/test-env-setup.sh b/plugins/woocommerce/tests/e2e-pw/bin/test-env-setup.sh index 95bff22a0d8..52ed55e49fa 100755 --- a/plugins/woocommerce/tests/e2e-pw/bin/test-env-setup.sh +++ b/plugins/woocommerce/tests/e2e-pw/bin/test-env-setup.sh @@ -38,8 +38,5 @@ if [ $ENABLE_TRACKING == 1 ]; then wp option update woocommerce_allow_tracking 'yes' fi -echo -e 'Disabling coming soon option\n' -wp option update woocommerce_coming_soon 'no' - echo -e 'Upload test images \n' wp media import './test-data/images/image-01.png' './test-data/images/image-02.png' './test-data/images/image-03.png' From ad1b233a9cf3f18e14911f80013f0e7a32ce61b4 Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Tue, 20 Aug 2024 14:22:58 +0800 Subject: [PATCH 020/185] Update AdditionalPayments task to use default gateway suggestion (#50674) * Add new default spec function * Changelog * Add a new method to get cached or default * Add test * Update comment * Revert comment * Update docblock * Lint * Typo * Set specs to default when marketplace suggestion is disabled * Update tests --- ...3-additional-payments-use-default-gateways | 4 ++ .../Tasks/AdditionalPayments.php | 2 +- .../PaymentGatewaySuggestions/Init.php | 25 ++++++++ ...mentGatewaySuggestionsDataSourcePoller.php | 2 +- .../Admin/RemoteSpecs/DataSourcePoller.php | 23 +++++++ .../payment-gateway-suggestions.php | 63 +++++++++++++++++++ 6 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-50543-additional-payments-use-default-gateways diff --git a/plugins/woocommerce/changelog/fix-50543-additional-payments-use-default-gateways b/plugins/woocommerce/changelog/fix-50543-additional-payments-use-default-gateways new file mode 100644 index 00000000000..ef2ef6f4773 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50543-additional-payments-use-default-gateways @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Update AdditionalPayments task to use default payment gateways diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php index 672b9a4a932..f5cdd68fedd 100644 --- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php +++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php @@ -188,7 +188,7 @@ class AdditionalPayments extends Payments { */ private static function get_suggestion_gateways( $filter_by = 'category_additional' ) { $country = wc_get_base_location()['country']; - $plugin_suggestions = Init::get_suggestions(); + $plugin_suggestions = Init::get_cached_or_default_suggestions(); $plugin_suggestions = array_filter( $plugin_suggestions, function( $plugin ) use ( $country, $filter_by ) { diff --git a/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/Init.php b/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/Init.php index 581f86b80b8..b6a7712aa18 100644 --- a/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/Init.php +++ b/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/Init.php @@ -61,6 +61,31 @@ class Init extends RemoteSpecsEngine { return $specs_to_return; } + /** + * Gets either cached or default suggestions. + * + * @return array + */ + public static function get_cached_or_default_suggestions() { + $specs = 'no' === get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) + ? DefaultPaymentGateways::get_all() + : PaymentGatewaySuggestionsDataSourcePoller::get_instance()->get_cached_specs(); + + if ( ! is_array( $specs ) || 0 === count( $specs ) ) { + $specs = DefaultPaymentGateways::get_all(); + } + /** + * Allows filtering of payment gateway suggestion specs + * + * @since 6.4.0 + * + * @param array Gateway specs. + */ + $specs = apply_filters( 'woocommerce_admin_payment_gateway_suggestion_specs', $specs ); + $results = EvaluateSuggestion::evaluate_specs( $specs ); + return $results['suggestions']; + } + /** * Delete the specs transient. */ diff --git a/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/PaymentGatewaySuggestionsDataSourcePoller.php b/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/PaymentGatewaySuggestionsDataSourcePoller.php index 5e3608b635d..d53ac724afd 100644 --- a/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/PaymentGatewaySuggestionsDataSourcePoller.php +++ b/plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/PaymentGatewaySuggestionsDataSourcePoller.php @@ -2,7 +2,7 @@ namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions; -use Automattic\WooCommerce\Admin\DataSourcePoller; +use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller; /** * Specs data source poller class for payment gateway suggestions. diff --git a/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php b/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php index 0769d65ffa6..d0812fd5ffa 100644 --- a/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php +++ b/plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php @@ -126,6 +126,29 @@ abstract class DataSourcePoller { return false !== $specs ? $specs : array(); } + /** + * Gets specs from cache if it exists. + * + * @return array list of specs. + */ + public function get_cached_specs() { + $locale = get_user_locale(); + $specs_group = get_transient( $this->args['transient_name'] ) ?? array(); + $specs = isset( $specs_group[ $locale ] ) ? $specs_group[ $locale ] : null; + + /** + * Filter specs. + * + * @param array $specs List of specs. + * @param string $this->id Spec identifier. + * + * @since 8.8.0 + */ + $specs = apply_filters( self::FILTER_NAME_SPECS, $specs, $this->id ); + + return false !== $specs ? $specs : array(); + } + /** * Reads the data sources for specs and persists those specs. * diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/payment-gateway-suggestions.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/payment-gateway-suggestions.php index 74f18eb6f30..728c78ce286 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/payment-gateway-suggestions.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/payment-gateway-suggestions.php @@ -117,6 +117,69 @@ class WC_Admin_Tests_PaymentGatewaySuggestions_Init extends WC_Unit_Test_Case { $this->assertEquals( $expected_suggestions[1]['id'], $suggestions[1]->id ); } + /** + * Test that specs are read from cache when they exist. + */ + public function test_cached_or_default_suggestions_when_cache_exist() { + // Arrange. + $expected_suggestions = array( + array( + 'id' => 'mock-gateway1', + ), + array( + 'id' => 'mock-gateway2', + ), + ); + set_transient( + 'woocommerce_admin_' . PaymentGatewaySuggestionsDataSourcePoller::ID . '_specs', + array( + 'en_US' => $expected_suggestions, + ) + ); + + // Act. + $suggestions = PaymentGatewaySuggestions::get_cached_or_default_suggestions(); + + // Assert. + $this->assertCount( count( $expected_suggestions ), $suggestions ); + $this->assertEquals( $expected_suggestions[0]['id'], $suggestions[0]->id ); + $this->assertEquals( $expected_suggestions[1]['id'], $suggestions[1]->id ); + } + + /** + * Test that specs are read from default when cache is empty. + */ + public function test_cached_or_default_suggestions_when_cache_empty() { + // Arrange. + PaymentGatewaySuggestionsDataSourcePoller::get_instance()->delete_specs_transient(); + + // Act. + $suggestions = PaymentGatewaySuggestions::get_cached_or_default_suggestions(); + + // Assert. + $default_suggestions = EvaluateSuggestion::evaluate_specs( DefaultPaymentGateways::get_all() )['suggestions']; + + $this->assertEquals( $default_suggestions, $suggestions ); + } + + + /** + * Test that default gateways are provided when remote sources don't exist. + */ + public function test_cached_or_default_suggestions_when_marketplace_suggestions_off() { + // Arrange. + update_option( 'woocommerce_show_marketplace_suggestions', 'no' ); + PaymentGatewaySuggestionsDataSourcePoller::get_instance()->delete_specs_transient(); + + // Act. + $suggestions = PaymentGatewaySuggestions::get_cached_or_default_suggestions(); + $default_suggestions = EvaluateSuggestion::evaluate_specs( DefaultPaymentGateways::get_all() )['suggestions']; + + // Assert. + $this->assertEquals( $suggestions, $default_suggestions ); + } + + /** * Test that non-matched suggestions are not shown. */ From 6bac54ad82b84c0de18bcadd2f9eb4edd16f72ae Mon Sep 17 00:00:00 2001 From: RJ <27843274+rjchow@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:39:13 +0800 Subject: [PATCH 021/185] Revert "Prevent initializing coming soon feature if it's already initialized" (#50783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "Prevent initializing coming soon feature if it's already initialized …" This reverts commit bcf1a38a585030ac5f5b4445017d3c45a0efb378. --- plugins/woocommerce/changelog/update-lys-init-coming-soon | 4 ---- plugins/woocommerce/src/Admin/API/LaunchYourStore.php | 5 ----- 2 files changed, 9 deletions(-) delete mode 100644 plugins/woocommerce/changelog/update-lys-init-coming-soon diff --git a/plugins/woocommerce/changelog/update-lys-init-coming-soon b/plugins/woocommerce/changelog/update-lys-init-coming-soon deleted file mode 100644 index 07c3800ccea..00000000000 --- a/plugins/woocommerce/changelog/update-lys-init-coming-soon +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: tweak - -Prevent initializing coming soon feature if it's already initialized diff --git a/plugins/woocommerce/src/Admin/API/LaunchYourStore.php b/plugins/woocommerce/src/Admin/API/LaunchYourStore.php index 735e18bba64..3bc45b296c9 100644 --- a/plugins/woocommerce/src/Admin/API/LaunchYourStore.php +++ b/plugins/woocommerce/src/Admin/API/LaunchYourStore.php @@ -128,11 +128,6 @@ class LaunchYourStore { return; } - if ( false === get_option( 'woocommerce_store_pages_only', false ) ) { - // Coming soon already initialized. - return false; - } - $coming_soon = 'yes'; $store_pages_only = WCAdminHelper::is_site_fresh() ? 'no' : 'yes'; $private_link = 'no'; From 9b1d91c7d2fddc424e6047814cf1bb980e46bc89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Rinc=C3=B3n?= Date: Tue, 20 Aug 2024 09:11:20 +0200 Subject: [PATCH 022/185] CYS - Move the `ai/business-description` endpoint to woocommerce admin API (#50359) * CYS - Move the ai/store-title endpoint to woocommerce admin api * Add middleware and callback * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint error * CYS - Move the ai/business-description endpoint to woocommerce admin API * Use constant and normalize site title values * Add base AI Endpoint class * Fix lint error * Use the endpoint base class * Revert change * Add changefile(s) from automation for the following project(s): woocommerce * Add strict types --------- Co-authored-by: github-actions --- .../design-with-ai/services.ts | 2 +- .../50359-48150-move-business-desc-endpoint | 4 + .../src/Admin/API/AI/BusinessDescription.php | 84 ++++++++++++++++ plugins/woocommerce/src/Admin/API/Init.php | 1 + .../Routes/V1/AI/BusinessDescription.php | 97 ------------------- .../src/StoreApi/RoutesController.php | 1 - .../src/StoreApi/SchemaController.php | 1 - .../V1/AI/BusinessDescriptionSchema.php | 47 --------- 8 files changed, 90 insertions(+), 147 deletions(-) create mode 100644 plugins/woocommerce/changelog/50359-48150-move-business-desc-endpoint create mode 100644 plugins/woocommerce/src/Admin/API/AI/BusinessDescription.php delete mode 100644 plugins/woocommerce/src/StoreApi/Routes/V1/AI/BusinessDescription.php delete mode 100644 plugins/woocommerce/src/StoreApi/Schemas/V1/AI/BusinessDescriptionSchema.php diff --git a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts index 1f217e1db2d..8d43f47ae59 100644 --- a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts +++ b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts @@ -314,7 +314,7 @@ export const updateStorePatterns = async ( await Promise.all( [ ...productContents, apiFetch( { - path: '/wc/private/ai/business-description', + path: '/wc-admin/ai/business-description', method: 'POST', data: { business_description: diff --git a/plugins/woocommerce/changelog/50359-48150-move-business-desc-endpoint b/plugins/woocommerce/changelog/50359-48150-move-business-desc-endpoint new file mode 100644 index 00000000000..ead95b77bd3 --- /dev/null +++ b/plugins/woocommerce/changelog/50359-48150-move-business-desc-endpoint @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +CYS - Move the ai/business-description endpoint to woocommerce admin API \ No newline at end of file diff --git a/plugins/woocommerce/src/Admin/API/AI/BusinessDescription.php b/plugins/woocommerce/src/Admin/API/AI/BusinessDescription.php new file mode 100644 index 00000000000..430e695f7b0 --- /dev/null +++ b/plugins/woocommerce/src/Admin/API/AI/BusinessDescription.php @@ -0,0 +1,84 @@ +register( + array( + array( + 'methods' => \WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'update_business_description' ), + 'permission_callback' => array( Middleware::class, 'is_authorized' ), + 'args' => array( + 'business_description' => array( + 'description' => __( 'The business description for a given store.', 'woocommerce' ), + 'type' => 'string', + ), + ), + ), + 'schema' => array( $this, 'get_schema' ), + ) + ); + } + + /** + * Update the business description. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response|WP_Error Response object. + */ + public function update_business_description( $request ) { + + $business_description = $request->get_param( 'business_description' ); + + if ( ! $business_description ) { + return new WP_Error( + 'invalid_business_description', + __( 'Invalid business description.', 'woocommerce' ) + ); + } + + update_option( 'last_business_description_with_ai_content_generated', $business_description ); + + return rest_ensure_response( + array( + 'ai_content_generated' => true, + ) + ); + } + + /** + * Get the Business Description response. + * + * @return array + */ + public function get_schema() { + return array( + 'ai_content_generated' => true, + ); + } +} diff --git a/plugins/woocommerce/src/Admin/API/Init.php b/plugins/woocommerce/src/Admin/API/Init.php index d8c35352996..4750b156c41 100644 --- a/plugins/woocommerce/src/Admin/API/Init.php +++ b/plugins/woocommerce/src/Admin/API/Init.php @@ -87,6 +87,7 @@ class Init { 'Automattic\WooCommerce\Admin\API\MobileAppMagicLink', 'Automattic\WooCommerce\Admin\API\ShippingPartnerSuggestions', 'Automattic\WooCommerce\Admin\API\AI\StoreTitle', + 'Automattic\WooCommerce\Admin\API\AI\BusinessDescription', ); } diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/BusinessDescription.php b/plugins/woocommerce/src/StoreApi/Routes/V1/AI/BusinessDescription.php deleted file mode 100644 index 79e5a221380..00000000000 --- a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/BusinessDescription.php +++ /dev/null @@ -1,97 +0,0 @@ - \WP_REST_Server::CREATABLE, - 'callback' => [ $this, 'get_response' ], - 'permission_callback' => [ Middleware::class, 'is_authorized' ], - 'args' => [ - 'business_description' => [ - 'description' => __( 'The business description for a given store.', 'woocommerce' ), - 'type' => 'string', - ], - ], - ], - 'schema' => [ $this->schema, 'get_public_item_schema' ], - 'allow_batch' => [ 'v1' => true ], - ]; - } - - /** - * Update the last business description. - * - * @param \WP_REST_Request $request Request object. - * - * @return bool|string|\WP_Error|\WP_REST_Response - */ - protected function get_route_post_response( \WP_REST_Request $request ) { - - $business_description = $request->get_param( 'business_description' ); - - if ( ! $business_description ) { - return $this->error_to_response( - new \WP_Error( - 'invalid_business_description', - __( 'Invalid business description.', 'woocommerce' ) - ) - ); - } - - update_option( 'last_business_description_with_ai_content_generated', $business_description ); - - return rest_ensure_response( - array( - 'ai_content_generated' => true, - ) - ); - } - -} diff --git a/plugins/woocommerce/src/StoreApi/RoutesController.php b/plugins/woocommerce/src/StoreApi/RoutesController.php index 986c29e925f..1e4b902a4f5 100644 --- a/plugins/woocommerce/src/StoreApi/RoutesController.php +++ b/plugins/woocommerce/src/StoreApi/RoutesController.php @@ -72,7 +72,6 @@ class RoutesController { Routes\V1\AI\Patterns::IDENTIFIER => Routes\V1\AI\Patterns::class, Routes\V1\AI\Product::IDENTIFIER => Routes\V1\AI\Product::class, Routes\V1\AI\Products::IDENTIFIER => Routes\V1\AI\Products::class, - Routes\V1\AI\BusinessDescription::IDENTIFIER => Routes\V1\AI\BusinessDescription::class, Routes\V1\AI\StoreInfo::IDENTIFIER => Routes\V1\AI\StoreInfo::class, Routes\V1\Patterns::IDENTIFIER => Routes\V1\Patterns::class, ], diff --git a/plugins/woocommerce/src/StoreApi/SchemaController.php b/plugins/woocommerce/src/StoreApi/SchemaController.php index e0a1cf843cc..170a151105b 100644 --- a/plugins/woocommerce/src/StoreApi/SchemaController.php +++ b/plugins/woocommerce/src/StoreApi/SchemaController.php @@ -58,7 +58,6 @@ class SchemaController { Schemas\V1\AI\PatternsSchema::IDENTIFIER => Schemas\V1\AI\PatternsSchema::class, Schemas\V1\AI\ProductSchema::IDENTIFIER => Schemas\V1\AI\ProductSchema::class, Schemas\V1\AI\ProductsSchema::IDENTIFIER => Schemas\V1\AI\ProductsSchema::class, - Schemas\V1\AI\BusinessDescriptionSchema::IDENTIFIER => Schemas\V1\AI\BusinessDescriptionSchema::class, Schemas\V1\AI\StoreInfoSchema::IDENTIFIER => Schemas\V1\AI\StoreInfoSchema::class, Schemas\V1\PatternsSchema::IDENTIFIER => Schemas\V1\PatternsSchema::class, ], diff --git a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/BusinessDescriptionSchema.php b/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/BusinessDescriptionSchema.php deleted file mode 100644 index b628fe9c33a..00000000000 --- a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/BusinessDescriptionSchema.php +++ /dev/null @@ -1,47 +0,0 @@ - true, - ]; - } -} From ba6f81c4861d0f2de4998317bfa2c02ca035dd74 Mon Sep 17 00:00:00 2001 From: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com> Date: Tue, 20 Aug 2024 08:38:08 +0100 Subject: [PATCH 023/185] [ci-jobs] Adds --list and --json options to save jobs output (#50684) --- tools/monorepo-utils/dist/index.js | 2 +- tools/monorepo-utils/src/ci-jobs/index.ts | 53 +++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/tools/monorepo-utils/dist/index.js b/tools/monorepo-utils/dist/index.js index 2b4523c66b8..4a8bc32f062 100644 --- a/tools/monorepo-utils/dist/index.js +++ b/tools/monorepo-utils/dist/index.js @@ -1,2 +1,2 @@ /*! For license information please see index.js.LICENSE.txt */ -(()=>{var __webpack_modules__={4797:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i),Object.defineProperty(e,s,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.hasOwnProperty.call(e,i)&&s(t,e,i);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.issue=t.issueCommand=void 0;const o=n(i(22037)),a=i(54106);function c(e,t,i){const s=new l(e,t,i);process.stdout.write(s.toString()+o.EOL)}t.issueCommand=c,t.issue=function(e,t=""){c(e,{},t)};class l{constructor(e,t,i){e||(e="missing.command"),this.command=e,this.properties=t,this.message=i}toString(){let e="::"+this.command;if(this.properties&&Object.keys(this.properties).length>0){e+=" ";let i=!0;for(const s in this.properties)if(this.properties.hasOwnProperty(s)){const r=this.properties[s];r&&(i?i=!1:e+=",",e+=`${s}=${t=r,a.toCommandValue(t).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}`)}}var t;return e+=`::${function(e){return a.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}(this.message)}`,e}}},57995:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i),Object.defineProperty(e,s,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.hasOwnProperty.call(e,i)&&s(t,e,i);return r(t,e),t},o=this&&this.__awaiter||function(e,t,i,s){return new(i||(i=Promise))((function(r,n){function o(e){try{c(s.next(e))}catch(e){n(e)}}function a(e){try{c(s.throw(e))}catch(e){n(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(o,a)}c((s=s.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.getIDToken=t.getState=t.saveState=t.group=t.endGroup=t.startGroup=t.info=t.notice=t.warning=t.error=t.debug=t.isDebug=t.setFailed=t.setCommandEcho=t.setOutput=t.getBooleanInput=t.getMultilineInput=t.getInput=t.addPath=t.setSecret=t.exportVariable=t.ExitCode=void 0;const a=i(4797),c=i(8096),l=i(54106),p=n(i(22037)),A=n(i(71017)),u=i(271);var d;function h(e,t){const i=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(t&&t.required&&!i)throw new Error(`Input required and not supplied: ${e}`);return t&&!1===t.trimWhitespace?i:i.trim()}function m(e,t={}){a.issueCommand("error",l.toCommandProperties(t),e instanceof Error?e.toString():e)}function g(e){a.issue("group",e)}function f(){a.issue("endgroup")}!function(e){e[e.Success=0]="Success",e[e.Failure=1]="Failure"}(d=t.ExitCode||(t.ExitCode={})),t.exportVariable=function(e,t){const i=l.toCommandValue(t);if(process.env[e]=i,process.env.GITHUB_ENV)return c.issueFileCommand("ENV",c.prepareKeyValueMessage(e,t));a.issueCommand("set-env",{name:e},i)},t.setSecret=function(e){a.issueCommand("add-mask",{},e)},t.addPath=function(e){process.env.GITHUB_PATH?c.issueFileCommand("PATH",e):a.issueCommand("add-path",{},e),process.env.PATH=`${e}${A.delimiter}${process.env.PATH}`},t.getInput=h,t.getMultilineInput=function(e,t){const i=h(e,t).split("\n").filter((e=>""!==e));return t&&!1===t.trimWhitespace?i:i.map((e=>e.trim()))},t.getBooleanInput=function(e,t){const i=h(e,t);if(["true","True","TRUE"].includes(i))return!0;if(["false","False","FALSE"].includes(i))return!1;throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${e}\nSupport boolean input list: \`true | True | TRUE | false | False | FALSE\``)},t.setOutput=function(e,t){if(process.env.GITHUB_OUTPUT)return c.issueFileCommand("OUTPUT",c.prepareKeyValueMessage(e,t));process.stdout.write(p.EOL),a.issueCommand("set-output",{name:e},l.toCommandValue(t))},t.setCommandEcho=function(e){a.issue("echo",e?"on":"off")},t.setFailed=function(e){process.exitCode=d.Failure,m(e)},t.isDebug=function(){return"1"===process.env.RUNNER_DEBUG},t.debug=function(e){a.issueCommand("debug",{},e)},t.error=m,t.warning=function(e,t={}){a.issueCommand("warning",l.toCommandProperties(t),e instanceof Error?e.toString():e)},t.notice=function(e,t={}){a.issueCommand("notice",l.toCommandProperties(t),e instanceof Error?e.toString():e)},t.info=function(e){process.stdout.write(e+p.EOL)},t.startGroup=g,t.endGroup=f,t.group=function(e,t){return o(this,void 0,void 0,(function*(){let i;g(e);try{i=yield t()}finally{f()}return i}))},t.saveState=function(e,t){if(process.env.GITHUB_STATE)return c.issueFileCommand("STATE",c.prepareKeyValueMessage(e,t));a.issueCommand("save-state",{name:e},l.toCommandValue(t))},t.getState=function(e){return process.env[`STATE_${e}`]||""},t.getIDToken=function(e){return o(this,void 0,void 0,(function*(){return yield u.OidcClient.getIDToken(e)}))};var E=i(26163);Object.defineProperty(t,"summary",{enumerable:!0,get:function(){return E.summary}});var C=i(26163);Object.defineProperty(t,"markdownSummary",{enumerable:!0,get:function(){return C.markdownSummary}});var y=i(56520);Object.defineProperty(t,"toPosixPath",{enumerable:!0,get:function(){return y.toPosixPath}}),Object.defineProperty(t,"toWin32Path",{enumerable:!0,get:function(){return y.toWin32Path}}),Object.defineProperty(t,"toPlatformPath",{enumerable:!0,get:function(){return y.toPlatformPath}})},8096:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i),Object.defineProperty(e,s,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.hasOwnProperty.call(e,i)&&s(t,e,i);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.prepareKeyValueMessage=t.issueFileCommand=void 0;const o=n(i(57147)),a=n(i(22037)),c=i(68040),l=i(54106);t.issueFileCommand=function(e,t){const i=process.env[`GITHUB_${e}`];if(!i)throw new Error(`Unable to find environment variable for file command ${e}`);if(!o.existsSync(i))throw new Error(`Missing file at path: ${i}`);o.appendFileSync(i,`${l.toCommandValue(t)}${a.EOL}`,{encoding:"utf8"})},t.prepareKeyValueMessage=function(e,t){const i=`ghadelimiter_${c.v4()}`,s=l.toCommandValue(t);if(e.includes(i))throw new Error(`Unexpected input: name should not contain the delimiter "${i}"`);if(s.includes(i))throw new Error(`Unexpected input: value should not contain the delimiter "${i}"`);return`${e}<<${i}${a.EOL}${s}${a.EOL}${i}`}},271:function(e,t,i){"use strict";var s=this&&this.__awaiter||function(e,t,i,s){return new(i||(i=Promise))((function(r,n){function o(e){try{c(s.next(e))}catch(e){n(e)}}function a(e){try{c(s.throw(e))}catch(e){n(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(o,a)}c((s=s.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.OidcClient=void 0;const r=i(48543),n=i(65343),o=i(57995);class a{static createHttpClient(e=!0,t=10){const i={allowRetries:e,maxRetries:t};return new r.HttpClient("actions/oidc-client",[new n.BearerCredentialHandler(a.getRequestToken())],i)}static getRequestToken(){const e=process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;if(!e)throw new Error("Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable");return e}static getIDTokenUrl(){const e=process.env.ACTIONS_ID_TOKEN_REQUEST_URL;if(!e)throw new Error("Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable");return e}static getCall(e){var t;return s(this,void 0,void 0,(function*(){const i=a.createHttpClient(),s=yield i.getJson(e).catch((e=>{throw new Error(`Failed to get ID Token. \n \n Error Code : ${e.statusCode}\n \n Error Message: ${e.message}`)})),r=null===(t=s.result)||void 0===t?void 0:t.value;if(!r)throw new Error("Response json body do not have ID Token field");return r}))}static getIDToken(e){return s(this,void 0,void 0,(function*(){try{let t=a.getIDTokenUrl();e&&(t=`${t}&audience=${encodeURIComponent(e)}`),o.debug(`ID token url is ${t}`);const i=yield a.getCall(t);return o.setSecret(i),i}catch(e){throw new Error(`Error message: ${e.message}`)}}))}}t.OidcClient=a},56520:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i),Object.defineProperty(e,s,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.hasOwnProperty.call(e,i)&&s(t,e,i);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.toPlatformPath=t.toWin32Path=t.toPosixPath=void 0;const o=n(i(71017));t.toPosixPath=function(e){return e.replace(/[\\]/g,"/")},t.toWin32Path=function(e){return e.replace(/[/]/g,"\\")},t.toPlatformPath=function(e){return e.replace(/[/\\]/g,o.sep)}},26163:function(e,t,i){"use strict";var s=this&&this.__awaiter||function(e,t,i,s){return new(i||(i=Promise))((function(r,n){function o(e){try{c(s.next(e))}catch(e){n(e)}}function a(e){try{c(s.throw(e))}catch(e){n(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(o,a)}c((s=s.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.summary=t.markdownSummary=t.SUMMARY_DOCS_URL=t.SUMMARY_ENV_VAR=void 0;const r=i(22037),n=i(57147),{access:o,appendFile:a,writeFile:c}=n.promises;t.SUMMARY_ENV_VAR="GITHUB_STEP_SUMMARY",t.SUMMARY_DOCS_URL="https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary";const l=new class{constructor(){this._buffer=""}filePath(){return s(this,void 0,void 0,(function*(){if(this._filePath)return this._filePath;const e=process.env[t.SUMMARY_ENV_VAR];if(!e)throw new Error(`Unable to find environment variable for $${t.SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.`);try{yield o(e,n.constants.R_OK|n.constants.W_OK)}catch(t){throw new Error(`Unable to access summary file: '${e}'. Check if the file has correct read/write permissions.`)}return this._filePath=e,this._filePath}))}wrap(e,t,i={}){const s=Object.entries(i).map((([e,t])=>` ${e}="${t}"`)).join("");return t?`<${e}${s}>${t}`:`<${e}${s}>`}write(e){return s(this,void 0,void 0,(function*(){const t=!!(null==e?void 0:e.overwrite),i=yield this.filePath(),s=t?c:a;return yield s(i,this._buffer,{encoding:"utf8"}),this.emptyBuffer()}))}clear(){return s(this,void 0,void 0,(function*(){return this.emptyBuffer().write({overwrite:!0})}))}stringify(){return this._buffer}isEmptyBuffer(){return 0===this._buffer.length}emptyBuffer(){return this._buffer="",this}addRaw(e,t=!1){return this._buffer+=e,t?this.addEOL():this}addEOL(){return this.addRaw(r.EOL)}addCodeBlock(e,t){const i=Object.assign({},t&&{lang:t}),s=this.wrap("pre",this.wrap("code",e),i);return this.addRaw(s).addEOL()}addList(e,t=!1){const i=t?"ol":"ul",s=e.map((e=>this.wrap("li",e))).join(""),r=this.wrap(i,s);return this.addRaw(r).addEOL()}addTable(e){const t=e.map((e=>{const t=e.map((e=>{if("string"==typeof e)return this.wrap("td",e);const{header:t,data:i,colspan:s,rowspan:r}=e,n=t?"th":"td",o=Object.assign(Object.assign({},s&&{colspan:s}),r&&{rowspan:r});return this.wrap(n,i,o)})).join("");return this.wrap("tr",t)})).join(""),i=this.wrap("table",t);return this.addRaw(i).addEOL()}addDetails(e,t){const i=this.wrap("details",this.wrap("summary",e)+t);return this.addRaw(i).addEOL()}addImage(e,t,i){const{width:s,height:r}=i||{},n=Object.assign(Object.assign({},s&&{width:s}),r&&{height:r}),o=this.wrap("img",null,Object.assign({src:e,alt:t},n));return this.addRaw(o).addEOL()}addHeading(e,t){const i=`h${t}`,s=["h1","h2","h3","h4","h5","h6"].includes(i)?i:"h1",r=this.wrap(s,e);return this.addRaw(r).addEOL()}addSeparator(){const e=this.wrap("hr",null);return this.addRaw(e).addEOL()}addBreak(){const e=this.wrap("br",null);return this.addRaw(e).addEOL()}addQuote(e,t){const i=Object.assign({},t&&{cite:t}),s=this.wrap("blockquote",e,i);return this.addRaw(s).addEOL()}addLink(e,t){const i=this.wrap("a",e,{href:t});return this.addRaw(i).addEOL()}};t.markdownSummary=l,t.summary=l},54106:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.toCommandProperties=t.toCommandValue=void 0,t.toCommandValue=function(e){return null==e?"":"string"==typeof e||e instanceof String?e:JSON.stringify(e)},t.toCommandProperties=function(e){return Object.keys(e).length?{title:e.title,file:e.file,line:e.startLine,endLine:e.endLine,col:e.startColumn,endColumn:e.endColumn}:{}}},65343:function(e,t){"use strict";var i=this&&this.__awaiter||function(e,t,i,s){return new(i||(i=Promise))((function(r,n){function o(e){try{c(s.next(e))}catch(e){n(e)}}function a(e){try{c(s.throw(e))}catch(e){n(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(o,a)}c((s=s.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.PersonalAccessTokenCredentialHandler=t.BearerCredentialHandler=t.BasicCredentialHandler=void 0,t.BasicCredentialHandler=class{constructor(e,t){this.username=e,this.password=t}prepareRequest(e){if(!e.headers)throw Error("The request has no headers");e.headers.Authorization=`Basic ${Buffer.from(`${this.username}:${this.password}`).toString("base64")}`}canHandleAuthentication(){return!1}handleAuthentication(){return i(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}},t.BearerCredentialHandler=class{constructor(e){this.token=e}prepareRequest(e){if(!e.headers)throw Error("The request has no headers");e.headers.Authorization=`Bearer ${this.token}`}canHandleAuthentication(){return!1}handleAuthentication(){return i(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}},t.PersonalAccessTokenCredentialHandler=class{constructor(e){this.token=e}prepareRequest(e){if(!e.headers)throw Error("The request has no headers");e.headers.Authorization=`Basic ${Buffer.from(`PAT:${this.token}`).toString("base64")}`}canHandleAuthentication(){return!1}handleAuthentication(){return i(this,void 0,void 0,(function*(){throw new Error("not implemented")}))}}},48543:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i);var r=Object.getOwnPropertyDescriptor(t,i);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[i]}}),Object.defineProperty(e,s,r)}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.prototype.hasOwnProperty.call(e,i)&&s(t,e,i);return r(t,e),t},o=this&&this.__awaiter||function(e,t,i,s){return new(i||(i=Promise))((function(r,n){function o(e){try{c(s.next(e))}catch(e){n(e)}}function a(e){try{c(s.throw(e))}catch(e){n(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(o,a)}c((s=s.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.HttpClient=t.isHttps=t.HttpClientResponse=t.HttpClientError=t.getProxyUrl=t.MediaTypes=t.Headers=t.HttpCodes=void 0;const a=n(i(13685)),c=n(i(95687)),l=n(i(20359)),p=n(i(42785)),A=i(90083);var u,d,h;!function(e){e[e.OK=200]="OK",e[e.MultipleChoices=300]="MultipleChoices",e[e.MovedPermanently=301]="MovedPermanently",e[e.ResourceMoved=302]="ResourceMoved",e[e.SeeOther=303]="SeeOther",e[e.NotModified=304]="NotModified",e[e.UseProxy=305]="UseProxy",e[e.SwitchProxy=306]="SwitchProxy",e[e.TemporaryRedirect=307]="TemporaryRedirect",e[e.PermanentRedirect=308]="PermanentRedirect",e[e.BadRequest=400]="BadRequest",e[e.Unauthorized=401]="Unauthorized",e[e.PaymentRequired=402]="PaymentRequired",e[e.Forbidden=403]="Forbidden",e[e.NotFound=404]="NotFound",e[e.MethodNotAllowed=405]="MethodNotAllowed",e[e.NotAcceptable=406]="NotAcceptable",e[e.ProxyAuthenticationRequired=407]="ProxyAuthenticationRequired",e[e.RequestTimeout=408]="RequestTimeout",e[e.Conflict=409]="Conflict",e[e.Gone=410]="Gone",e[e.TooManyRequests=429]="TooManyRequests",e[e.InternalServerError=500]="InternalServerError",e[e.NotImplemented=501]="NotImplemented",e[e.BadGateway=502]="BadGateway",e[e.ServiceUnavailable=503]="ServiceUnavailable",e[e.GatewayTimeout=504]="GatewayTimeout"}(u||(t.HttpCodes=u={})),function(e){e.Accept="accept",e.ContentType="content-type"}(d||(t.Headers=d={})),function(e){e.ApplicationJson="application/json"}(h||(t.MediaTypes=h={})),t.getProxyUrl=function(e){const t=l.getProxyUrl(new URL(e));return t?t.href:""};const m=[u.MovedPermanently,u.ResourceMoved,u.SeeOther,u.TemporaryRedirect,u.PermanentRedirect],g=[u.BadGateway,u.ServiceUnavailable,u.GatewayTimeout],f=["OPTIONS","GET","DELETE","HEAD"];class E extends Error{constructor(e,t){super(e),this.name="HttpClientError",this.statusCode=t,Object.setPrototypeOf(this,E.prototype)}}t.HttpClientError=E;class C{constructor(e){this.message=e}readBody(){return o(this,void 0,void 0,(function*(){return new Promise((e=>o(this,void 0,void 0,(function*(){let t=Buffer.alloc(0);this.message.on("data",(e=>{t=Buffer.concat([t,e])})),this.message.on("end",(()=>{e(t.toString())}))}))))}))}readBodyBuffer(){return o(this,void 0,void 0,(function*(){return new Promise((e=>o(this,void 0,void 0,(function*(){const t=[];this.message.on("data",(e=>{t.push(e)})),this.message.on("end",(()=>{e(Buffer.concat(t))}))}))))}))}}t.HttpClientResponse=C,t.isHttps=function(e){return"https:"===new URL(e).protocol},t.HttpClient=class{constructor(e,t,i){this._ignoreSslError=!1,this._allowRedirects=!0,this._allowRedirectDowngrade=!1,this._maxRedirects=50,this._allowRetries=!1,this._maxRetries=1,this._keepAlive=!1,this._disposed=!1,this.userAgent=e,this.handlers=t||[],this.requestOptions=i,i&&(null!=i.ignoreSslError&&(this._ignoreSslError=i.ignoreSslError),this._socketTimeout=i.socketTimeout,null!=i.allowRedirects&&(this._allowRedirects=i.allowRedirects),null!=i.allowRedirectDowngrade&&(this._allowRedirectDowngrade=i.allowRedirectDowngrade),null!=i.maxRedirects&&(this._maxRedirects=Math.max(i.maxRedirects,0)),null!=i.keepAlive&&(this._keepAlive=i.keepAlive),null!=i.allowRetries&&(this._allowRetries=i.allowRetries),null!=i.maxRetries&&(this._maxRetries=i.maxRetries))}options(e,t){return o(this,void 0,void 0,(function*(){return this.request("OPTIONS",e,null,t||{})}))}get(e,t){return o(this,void 0,void 0,(function*(){return this.request("GET",e,null,t||{})}))}del(e,t){return o(this,void 0,void 0,(function*(){return this.request("DELETE",e,null,t||{})}))}post(e,t,i){return o(this,void 0,void 0,(function*(){return this.request("POST",e,t,i||{})}))}patch(e,t,i){return o(this,void 0,void 0,(function*(){return this.request("PATCH",e,t,i||{})}))}put(e,t,i){return o(this,void 0,void 0,(function*(){return this.request("PUT",e,t,i||{})}))}head(e,t){return o(this,void 0,void 0,(function*(){return this.request("HEAD",e,null,t||{})}))}sendStream(e,t,i,s){return o(this,void 0,void 0,(function*(){return this.request(e,t,i,s)}))}getJson(e,t={}){return o(this,void 0,void 0,(function*(){t[d.Accept]=this._getExistingOrDefaultHeader(t,d.Accept,h.ApplicationJson);const i=yield this.get(e,t);return this._processResponse(i,this.requestOptions)}))}postJson(e,t,i={}){return o(this,void 0,void 0,(function*(){const s=JSON.stringify(t,null,2);i[d.Accept]=this._getExistingOrDefaultHeader(i,d.Accept,h.ApplicationJson),i[d.ContentType]=this._getExistingOrDefaultHeader(i,d.ContentType,h.ApplicationJson);const r=yield this.post(e,s,i);return this._processResponse(r,this.requestOptions)}))}putJson(e,t,i={}){return o(this,void 0,void 0,(function*(){const s=JSON.stringify(t,null,2);i[d.Accept]=this._getExistingOrDefaultHeader(i,d.Accept,h.ApplicationJson),i[d.ContentType]=this._getExistingOrDefaultHeader(i,d.ContentType,h.ApplicationJson);const r=yield this.put(e,s,i);return this._processResponse(r,this.requestOptions)}))}patchJson(e,t,i={}){return o(this,void 0,void 0,(function*(){const s=JSON.stringify(t,null,2);i[d.Accept]=this._getExistingOrDefaultHeader(i,d.Accept,h.ApplicationJson),i[d.ContentType]=this._getExistingOrDefaultHeader(i,d.ContentType,h.ApplicationJson);const r=yield this.patch(e,s,i);return this._processResponse(r,this.requestOptions)}))}request(e,t,i,s){return o(this,void 0,void 0,(function*(){if(this._disposed)throw new Error("Client has already been disposed.");const r=new URL(t);let n=this._prepareRequest(e,r,s);const o=this._allowRetries&&f.includes(e)?this._maxRetries+1:1;let a,c=0;do{if(a=yield this.requestRaw(n,i),a&&a.message&&a.message.statusCode===u.Unauthorized){let e;for(const t of this.handlers)if(t.canHandleAuthentication(a)){e=t;break}return e?e.handleAuthentication(this,n,i):a}let t=this._maxRedirects;for(;a.message.statusCode&&m.includes(a.message.statusCode)&&this._allowRedirects&&t>0;){const o=a.message.headers.location;if(!o)break;const c=new URL(o);if("https:"===r.protocol&&r.protocol!==c.protocol&&!this._allowRedirectDowngrade)throw new Error("Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.");if(yield a.readBody(),c.hostname!==r.hostname)for(const e in s)"authorization"===e.toLowerCase()&&delete s[e];n=this._prepareRequest(e,c,s),a=yield this.requestRaw(n,i),t--}if(!a.message.statusCode||!g.includes(a.message.statusCode))return a;c+=1,c{this.requestRawWithCallback(e,t,(function(e,t){e?s(e):t?i(t):s(new Error("Unknown error"))}))}))}))}requestRawWithCallback(e,t,i){"string"==typeof t&&(e.options.headers||(e.options.headers={}),e.options.headers["Content-Length"]=Buffer.byteLength(t,"utf8"));let s=!1;function r(e,t){s||(s=!0,i(e,t))}const n=e.httpModule.request(e.options,(e=>{r(void 0,new C(e))}));let o;n.on("socket",(e=>{o=e})),n.setTimeout(this._socketTimeout||18e4,(()=>{o&&o.end(),r(new Error(`Request timeout: ${e.options.path}`))})),n.on("error",(function(e){r(e)})),t&&"string"==typeof t&&n.write(t,"utf8"),t&&"string"!=typeof t?(t.on("close",(function(){n.end()})),t.pipe(n)):n.end()}getAgent(e){const t=new URL(e);return this._getAgent(t)}getAgentDispatcher(e){const t=new URL(e),i=l.getProxyUrl(t);if(i&&i.hostname)return this._getProxyAgentDispatcher(t,i)}_prepareRequest(e,t,i){const s={};s.parsedUrl=t;const r="https:"===s.parsedUrl.protocol;s.httpModule=r?c:a;const n=r?443:80;if(s.options={},s.options.host=s.parsedUrl.hostname,s.options.port=s.parsedUrl.port?parseInt(s.parsedUrl.port):n,s.options.path=(s.parsedUrl.pathname||"")+(s.parsedUrl.search||""),s.options.method=e,s.options.headers=this._mergeHeaders(i),null!=this.userAgent&&(s.options.headers["user-agent"]=this.userAgent),s.options.agent=this._getAgent(s.parsedUrl),this.handlers)for(const e of this.handlers)e.prepareRequest(s.options);return s}_mergeHeaders(e){return this.requestOptions&&this.requestOptions.headers?Object.assign({},y(this.requestOptions.headers),y(e||{})):y(e||{})}_getExistingOrDefaultHeader(e,t,i){let s;return this.requestOptions&&this.requestOptions.headers&&(s=y(this.requestOptions.headers)[t]),e[t]||s||i}_getAgent(e){let t;const i=l.getProxyUrl(e),s=i&&i.hostname;if(this._keepAlive&&s&&(t=this._proxyAgent),this._keepAlive&&!s&&(t=this._agent),t)return t;const r="https:"===e.protocol;let n=100;if(this.requestOptions&&(n=this.requestOptions.maxSockets||a.globalAgent.maxSockets),i&&i.hostname){const e={maxSockets:n,keepAlive:this._keepAlive,proxy:Object.assign(Object.assign({},(i.username||i.password)&&{proxyAuth:`${i.username}:${i.password}`}),{host:i.hostname,port:i.port})};let s;const o="https:"===i.protocol;s=r?o?p.httpsOverHttps:p.httpsOverHttp:o?p.httpOverHttps:p.httpOverHttp,t=s(e),this._proxyAgent=t}if(this._keepAlive&&!t){const e={keepAlive:this._keepAlive,maxSockets:n};t=r?new c.Agent(e):new a.Agent(e),this._agent=t}return t||(t=r?c.globalAgent:a.globalAgent),r&&this._ignoreSslError&&(t.options=Object.assign(t.options||{},{rejectUnauthorized:!1})),t}_getProxyAgentDispatcher(e,t){let i;if(this._keepAlive&&(i=this._proxyAgentDispatcher),i)return i;const s="https:"===e.protocol;return i=new A.ProxyAgent(Object.assign({uri:t.href,pipelining:this._keepAlive?1:0},(t.username||t.password)&&{token:`${t.username}:${t.password}`})),this._proxyAgentDispatcher=i,s&&this._ignoreSslError&&(i.options=Object.assign(i.options.requestTls||{},{rejectUnauthorized:!1})),i}_performExponentialBackoff(e){return o(this,void 0,void 0,(function*(){e=Math.min(10,e);const t=5*Math.pow(2,e);return new Promise((e=>setTimeout((()=>e()),t)))}))}_processResponse(e,t){return o(this,void 0,void 0,(function*(){return new Promise(((i,s)=>o(this,void 0,void 0,(function*(){const r=e.message.statusCode||0,n={statusCode:r,result:null,headers:{}};let o,a;r===u.NotFound&&i(n);try{a=yield e.readBody(),a&&a.length>0&&(o=t&&t.deserializeDates?JSON.parse(a,(function(e,t){if("string"==typeof t){const e=new Date(t);if(!isNaN(e.valueOf()))return e}return t})):JSON.parse(a),n.result=o),n.headers=e.message.headers}catch(e){}if(r>299){let e;e=o&&o.message?o.message:a&&a.length>0?a:`Failed request: (${r})`;const t=new E(e,r);t.result=n.result,s(t)}else i(n)}))))}))}};const y=e=>Object.keys(e).reduce(((t,i)=>(t[i.toLowerCase()]=e[i],t)),{})},20359:(e,t)=>{"use strict";function i(e){if(!e.hostname)return!1;if(function(e){const t=e.toLowerCase();return"localhost"===t||t.startsWith("127.")||t.startsWith("[::1]")||t.startsWith("[0:0:0:0:0:0:0:1]")}(e.hostname))return!0;const t=process.env.no_proxy||process.env.NO_PROXY||"";if(!t)return!1;let i;e.port?i=Number(e.port):"http:"===e.protocol?i=80:"https:"===e.protocol&&(i=443);const s=[e.hostname.toUpperCase()];"number"==typeof i&&s.push(`${s[0]}:${i}`);for(const e of t.split(",").map((e=>e.trim().toUpperCase())).filter((e=>e)))if("*"===e||s.some((t=>t===e||t.endsWith(`.${e}`)||e.startsWith(".")&&t.endsWith(`${e}`))))return!0;return!1}Object.defineProperty(t,"__esModule",{value:!0}),t.checkBypass=t.getProxyUrl=void 0,t.getProxyUrl=function(e){const t="https:"===e.protocol;if(i(e))return;const s=t?process.env.https_proxy||process.env.HTTPS_PROXY:process.env.http_proxy||process.env.HTTP_PROXY;if(s)try{return new URL(s)}catch(e){if(!s.startsWith("http://")&&!s.startsWith("https://"))return new URL(`http://${s}`)}},t.checkBypass=i},55763:(e,t,i)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){for(var i in e)t.hasOwnProperty(i)||(t[i]=e[i])}(i(20536))},20536:function(e,t,i){"use strict";var s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const r=i(57147),n=s(i(8856)).default("@kwsites/file-exists");t.exists=function(e,i=t.READABLE){return function(e,t,i){n("checking %s",e);try{const s=r.statSync(e);return s.isFile()&&t?(n("[OK] path represents a file"),!0):s.isDirectory()&&i?(n("[OK] path represents a directory"),!0):(n("[FAIL] path represents something other than a file or directory"),!1)}catch(e){if("ENOENT"===e.code)return n("[FAIL] path is not accessible: %o",e),!1;throw n("[FATAL] %o",e),e}}(e,(i&t.FILE)>0,(i&t.FOLDER)>0)},t.FILE=1,t.FOLDER=2,t.READABLE=t.FILE+t.FOLDER},39487:(e,t)=>{"use strict";function i(){let e,t,i="pending";return{promise:new Promise(((i,s)=>{e=i,t=s})),done(t){"pending"===i&&(i="resolved",e(t))},fail(e){"pending"===i&&(i="rejected",t(e))},get fulfilled(){return"pending"!==i},get status(){return i}}}Object.defineProperty(t,"__esModule",{value:!0}),t.createDeferred=t.deferred=void 0,t.deferred=i,t.createDeferred=i,t.default=i},61786:(e,t,i)=>{"use strict";var s,r=Object.create,n=Object.defineProperty,o=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,c=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,p=(e,t,i,s)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let r of a(t))l.call(e,r)||r===i||n(e,r,{get:()=>t[r],enumerable:!(s=o(t,r))||s.enumerable});return e},A={};((e,t)=>{for(var i in t)n(e,i,{get:t[i],enumerable:!0})})(A,{createAppAuth:()=>S,createOAuthUserAuth:()=>D.createOAuthUserAuth}),e.exports=(s=A,p(n({},"__esModule",{value:!0}),s));var u=i(21375),d=i(65683),h=i(62419),m=i(57751),g=(((e,t,i)=>{i=null!=e?r(c(e)):{},p(e&&e.__esModule?i:n(i,"default",{value:e,enumerable:!0}),e)})(i(62419)),i(67478));async function f({appId:e,privateKey:t,timeDifference:i}){try{const s=await(0,g.githubAppJwt)({id:+e,privateKey:t,now:i&&Math.floor(Date.now()/1e3)+i});return{type:"app",token:s.token,appId:s.appId,expiresAt:new Date(1e3*s.expiration).toISOString()}}catch(e){throw"-----BEGIN RSA PRIVATE KEY-----"===t?new Error("The 'privateKey` option contains only the first line '-----BEGIN RSA PRIVATE KEY-----'. If you are setting it using a `.env` file, make sure it is set on a single line with newlines replaced by '\n'"):e}}var E=i(65649);function C({installationId:e,permissions:t={},repositoryIds:i=[],repositoryNames:s=[]}){const r=Object.keys(t).sort().map((e=>"read"===t[e]?e:`${e}!`)).join(",");return[e,i.sort().join(","),s.join(","),r].filter(Boolean).join("|")}function y({installationId:e,token:t,createdAt:i,expiresAt:s,repositorySelection:r,permissions:n,repositoryIds:o,repositoryNames:a,singleFileName:c}){return Object.assign({type:"token",tokenType:"installation",token:t,installationId:e,permissions:n,createdAt:i,expiresAt:s,repositorySelection:r},o?{repositoryIds:o}:null,a?{repositoryNames:a}:null,c?{singleFileName:c}:null)}async function v(e,t,i){const s=Number(t.installationId||e.installationId);if(!s)throw new Error("[@octokit/auth-app] installationId option is required for installation authentication.");if(t.factory){const{type:i,factory:s,oauthApp:r,...n}={...e,...t};return s(n)}const r=Object.assign({installationId:s},t);if(!t.refresh){const t=await async function(e,t){const i=C(t),s=await e.get(i);if(!s)return;const[r,n,o,a,c,l]=s.split("|");return{token:r,createdAt:n,expiresAt:o,permissions:t.permissions||c.split(/,/).reduce(((e,t)=>(/!$/.test(t)?e[t.slice(0,-1)]="write":e[t]="read",e)),{}),repositoryIds:t.repositoryIds,repositoryNames:t.repositoryNames,singleFileName:l,repositorySelection:a}}(e.cache,r);if(t){const{token:e,createdAt:i,expiresAt:r,permissions:n,repositoryIds:o,repositoryNames:a,singleFileName:c,repositorySelection:l}=t;return y({installationId:s,token:e,createdAt:i,expiresAt:r,permissions:n,repositorySelection:l,repositoryIds:o,repositoryNames:a,singleFileName:c})}}const n=await f(e),o=i||e.request,{data:{token:a,expires_at:c,repositories:l,permissions:p,repository_selection:A,single_file:u}}=await o("POST /app/installations/{installation_id}/access_tokens",{installation_id:s,repository_ids:t.repositoryIds,repositories:t.repositoryNames,permissions:t.permissions,mediaType:{previews:["machine-man"]},headers:{authorization:`bearer ${n.token}`}}),d=p||{},h=A||"all",m=l?l.map((e=>e.id)):void 0,g=l?l.map((e=>e.name)):void 0,E=(new Date).toISOString();return await async function(e,t,i){const s=C(t),r=t.permissions?"":Object.keys(i.permissions).map((e=>`${e}${"write"===i.permissions[e]?"!":""}`)).join(","),n=[i.token,i.createdAt,i.expiresAt,i.repositorySelection,r,i.singleFileName].join("|");await e.set(s,n)}(e.cache,r,{token:a,createdAt:E,expiresAt:c,repositorySelection:h,permissions:d,repositoryIds:m,repositoryNames:g,singleFileName:u}),y({installationId:s,token:a,createdAt:E,expiresAt:c,repositorySelection:h,permissions:d,repositoryIds:m,repositoryNames:g,singleFileName:u})}async function I(e,t){switch(t.type){case"app":return f(e);case"oauth":e.log.warn(new m.Deprecation('[@octokit/auth-app] {type: "oauth"} is deprecated. Use {type: "oauth-app"} instead'));case"oauth-app":return e.oauthApp({type:"oauth-app"});case"installation":return v(e,{...t,type:"installation"});case"oauth-user":return e.oauthApp(t);default:throw new Error(`Invalid auth type: ${t.type}`)}}var B=i(3360);i(98838);var w=function(e){const t=`^(?:${["/app","/app/hook/config","/app/hook/deliveries","/app/hook/deliveries/{delivery_id}","/app/hook/deliveries/{delivery_id}/attempts","/app/installations","/app/installations/{installation_id}","/app/installations/{installation_id}/access_tokens","/app/installations/{installation_id}/suspended","/app/installation-requests","/marketplace_listing/accounts/{account_id}","/marketplace_listing/plan","/marketplace_listing/plans","/marketplace_listing/plans/{plan_id}/accounts","/marketplace_listing/stubbed/accounts/{account_id}","/marketplace_listing/stubbed/plan","/marketplace_listing/stubbed/plans","/marketplace_listing/stubbed/plans/{plan_id}/accounts","/orgs/{org}/installation","/repos/{owner}/{repo}/installation","/users/{username}/installation"].map((e=>e.split("/").map((e=>e.startsWith("{")?"(?:.+?)":e)).join("/"))).map((e=>`(?:${e})`)).join("|")})$`;return new RegExp(t,"i")}(),b=5e3;async function Q(e,t,i,s){const r=t.endpoint.merge(i,s),n=r.url;if(/\/login\/oauth\/access_token$/.test(n))return t(r);if(function(e){return!!e&&w.test(e.split("?")[0])}(n.replace(t.endpoint.DEFAULTS.baseUrl,""))){const{token:i}=await f(e);let s;r.headers.authorization=`bearer ${i}`;try{s=await t(r)}catch(i){if(function(e){return!(e.message.match(/'Expiration time' claim \('exp'\) must be a numeric value representing the future time at which the assertion expires/)||e.message.match(/'Issued at' claim \('iat'\) must be an Integer representing the time that the assertion was issued/))}(i))throw i;if(void 0===i.response.headers.date)throw i;const s=Math.floor((Date.parse(i.response.headers.date)-Date.parse((new Date).toString()))/1e3);e.log.warn(i.message),e.log.warn(`[@octokit/auth-app] GitHub API time and system time are different by ${s} seconds. Retrying request with the difference accounted for.`);const{token:n}=await f({...e,timeDifference:s});return r.headers.authorization=`bearer ${n}`,t(r)}return s}if((0,B.requiresBasicAuth)(n)){const i=await e.oauthApp({type:"oauth-app"});return r.headers.authorization=i.headers.authorization,t(r)}const{token:o,createdAt:a}=await v(e,{},t);return r.headers.authorization=`token ${o}`,x(e,t,r,a)}async function x(e,t,i,s,r=0){const n=+new Date-+new Date(s);try{return await t(i)}catch(o){if(401!==o.status)throw o;if(n>=b)throw r>0&&(o.message=`After ${r} retries within ${n/1e3}s of creating the installation access token, the response remains 401. At this point, the cause may be an authentication problem or a system outage. Please check https://www.githubstatus.com for status information`),o;const a=1e3*++r;return e.log.warn(`[@octokit/auth-app] Retrying after 401 response to account for token replication delay (retry: ${r}, wait: ${a/1e3}s)`),await new Promise((e=>setTimeout(e,a))),x(e,t,i,s,r)}}var k="6.1.1",D=i(3360);function S(e){if(!e.appId)throw new Error("[@octokit/auth-app] appId option is required");if(!Number.isFinite(+e.appId))throw new Error("[@octokit/auth-app] appId option must be a number or numeric string");if(!e.privateKey)throw new Error("[@octokit/auth-app] privateKey option is required");if("installationId"in e&&!e.installationId)throw new Error("[@octokit/auth-app] installationId is set to a falsy value");const t=Object.assign({warn:console.warn.bind(console)},e.log),i=e.request||d.request.defaults({headers:{"user-agent":`octokit-auth-app.js/${k} ${(0,u.getUserAgent)()}`}}),s=Object.assign({request:i,cache:new E.LRUCache({max:15e3,ttl:354e4})},e,e.installationId?{installationId:Number(e.installationId)}:{},{log:t,oauthApp:(0,h.createOAuthAppAuth)({clientType:"github-app",clientId:e.clientId||"",clientSecret:e.clientSecret||"",request:i})});return Object.assign(I.bind(null,s),{hook:Q.bind(null,s)})}},62419:(e,t,i)=>{"use strict";i.r(t),i.d(t,{createOAuthAppAuth:()=>u,createOAuthUserAuth:()=>a.createOAuthUserAuth});var s=i(21375),r=i(65683),n=i(96756),o=i.n(n),a=i(3360);async function c(e,t){if("oauth-app"===t.type)return{type:"oauth-app",clientId:e.clientId,clientSecret:e.clientSecret,clientType:e.clientType,headers:{authorization:`basic ${o()(`${e.clientId}:${e.clientSecret}`)}`}};if("factory"in t){const{type:i,...s}={...t,...e};return t.factory(s)}const i={clientId:e.clientId,clientSecret:e.clientSecret,request:e.request,...t};return(e.clientType,await(0,a.createOAuthUserAuth)({...i,clientType:e.clientType}))()}var l=i(90420);async function p(e,t,i,s){let r=t.endpoint.merge(i,s);if(/\/login\/(oauth\/access_token|device\/code)$/.test(r.url))return t(r);if("github-app"===e.clientType&&!(0,l.X)(r.url))throw new Error(`[@octokit/auth-oauth-app] GitHub Apps cannot use their client ID/secret for basic authentication for endpoints other than "/applications/{client_id}/**". "${r.method} ${r.url}" is not supported.`);const n=o()(`${e.clientId}:${e.clientSecret}`);r.headers.authorization=`basic ${n}`;try{return await t(r)}catch(e){if(401!==e.status)throw e;throw e.message=`[@octokit/auth-oauth-app] "${r.method} ${r.url}" does not support clientId/clientSecret basic authentication.`,e}}const A="7.1.0";function u(e){const t=Object.assign({request:r.request.defaults({headers:{"user-agent":`octokit-auth-oauth-app.js/${A} ${(0,s.getUserAgent)()}`}}),clientType:"oauth-app"},e);return Object.assign(c.bind(null,t),{hook:p.bind(null,t)})}},3360:(e,t,i)=>{"use strict";i.r(t),i.d(t,{createOAuthUserAuth:()=>Q,requiresBasicAuth:()=>w.X});var s=i(21375),r=i(65683);const n="4.1.0";var o=i(63855),a=i(85579);async function c(e,t){const i=function(e,t){if(!0===t.refresh)return!1;if(!e.authentication)return!1;if("github-app"===e.clientType)return e.authentication;const i=e.authentication;return("scopes"in t&&t.scopes||e.scopes).join(" ")===i.scopes.join(" ")&&i}(e,t.auth);if(i)return i;const{data:s}=await(0,o.T)({clientType:e.clientType,clientId:e.clientId,request:t.request||e.request,scopes:t.auth.scopes||e.scopes});await e.onVerification(s);const r=await p(t.request||e.request,e.clientId,e.clientType,s);return e.authentication=r,r}async function l(e){await new Promise((t=>setTimeout(t,1e3*e)))}async function p(e,t,i,s){try{const r={clientId:t,request:e,code:s.device_code},{authentication:n}="oauth-app"===i?await(0,a.i)({...r,clientType:"oauth-app"}):await(0,a.i)({...r,clientType:"github-app"});return{type:"token",tokenType:"oauth",...n}}catch(r){if(!r.response)throw r;const n=r.response.data.error;if("authorization_pending"===n)return await l(s.interval),p(e,t,i,s);if("slow_down"===n)return await l(s.interval+5),p(e,t,i,s);throw r}}async function A(e,t){return c(e,{auth:t})}async function u(e,t,i,s){let r=t.endpoint.merge(i,s);if(/\/login\/(oauth\/access_token|device\/code)$/.test(r.url))return t(r);const{token:n}=await c(e,{request:t,auth:{type:"oauth"}});return r.headers.authorization=`token ${n}`,t(r)}const d="6.1.0";function h(e){const t=e.request||r.request.defaults({headers:{"user-agent":`octokit-auth-oauth-device.js/${d} ${(0,s.getUserAgent)()}`}}),{request:i=t,...n}=e,o="github-app"===e.clientType?{...n,clientType:"github-app",request:i}:{...n,clientType:"oauth-app",request:i,scopes:e.scopes||[]};if(!e.clientId)throw new Error('[@octokit/auth-oauth-device] "clientId" option must be set (https://github.com/octokit/auth-oauth-device.js#usage)');if(!e.onVerification)throw new Error('[@octokit/auth-oauth-device] "onVerification" option must be a function (https://github.com/octokit/auth-oauth-device.js#usage)');return Object.assign(A.bind(null,o),{hook:u.bind(null,o)})}var m=i(71060);var g=i(27550),f=i(4923),E=i(9147),C=i(46886),y=i(62616);async function v(e,t={}){if(e.authentication||(e.authentication=(e.clientType,await async function(e){if("code"in e.strategyOptions){const{authentication:t}=await(0,m.y)({clientId:e.clientId,clientSecret:e.clientSecret,clientType:e.clientType,onTokenCreated:e.onTokenCreated,...e.strategyOptions,request:e.request});return{type:"token",tokenType:"oauth",...t}}if("onVerification"in e.strategyOptions){const t=h({clientType:e.clientType,clientId:e.clientId,onTokenCreated:e.onTokenCreated,...e.strategyOptions,request:e.request}),i=await t({type:"oauth"});return{clientSecret:e.clientSecret,...i}}if("token"in e.strategyOptions)return{type:"token",tokenType:"oauth",clientId:e.clientId,clientSecret:e.clientSecret,clientType:e.clientType,onTokenCreated:e.onTokenCreated,...e.strategyOptions};throw new Error("[@octokit/auth-oauth-user] Invalid strategy options")}(e))),e.authentication.invalid)throw new Error("[@octokit/auth-oauth-user] Token is invalid");const i=e.authentication;if("expiresAt"in i&&("refresh"===t.type||new Date(i.expiresAt){"use strict";i.d(t,{X:()=>r});const s=/\/applications\/[^/]+\/(token|grant)s?/;function r(e){return e&&s.test(e)}},37573:(e,t,i)=>{"use strict";async function s(e){return{type:"unauthenticated",reason:e}}i.r(t),i.d(t,{createUnauthenticatedAuth:()=>o});var r=/\babuse\b/i;async function n(e,t,i,s){const n=t.endpoint.merge(i,s);return t(n).catch((t=>{if(404===t.status)throw t.message=`Not found. May be due to lack of authentication. Reason: ${e}`,t;if(function(e){return 403===e.status&&!!e.response&&"0"===e.response.headers["x-ratelimit-remaining"]}(t))throw t.message=`API rate limit exceeded. This maybe caused by the lack of authentication. Reason: ${e}`,t;if(function(e){return 403===e.status&&r.test(e.message)}(t))throw t.message=`You have triggered an abuse detection mechanism. This maybe caused by the lack of authentication. Reason: ${e}`,t;if(401===t.status)throw t.message=`Unauthorized. "${n.method} ${n.url}" failed most likely due to lack of authentication. Reason: ${e}`,t;throw t.status>=400&&t.status<500&&(t.message=t.message.replace(/\.?$/,`. May be caused by lack of authentication (${e}).`)),t}))}var o=function(e){if(!e||!e.reason)throw new Error("[@octokit/auth-unauthenticated] No reason passed to createUnauthenticatedAuth");return Object.assign(s.bind(null,e.reason),{hook:n.bind(null,e.reason)})}},96049:(e,t,i)=>{"use strict";i.r(t),i.d(t,{Octokit:()=>I});var s=i(21375),r=i(8903),n=i(65683),o=class extends Error{constructor(e,t,i){super("Request failed due to following response errors:\n"+i.errors.map((e=>` - ${e.message}`)).join("\n")),this.request=e,this.headers=t,this.response=i,this.name="GraphqlResponseError",this.errors=i.errors,this.data=i.data,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},a=["method","baseUrl","url","headers","request","query","mediaType"],c=["query","method","url"],l=/\/api\/v3\/?$/;function p(e,t){const i=e.defaults(t);return Object.assign(((e,t)=>function(e,t,i){if(i){if("string"==typeof t&&"query"in i)return Promise.reject(new Error('[@octokit/graphql] "query" cannot be used as variable name'));for(const e in i)if(c.includes(e))return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}const s="string"==typeof t?Object.assign({query:t},i):t,r=Object.keys(s).reduce(((e,t)=>a.includes(t)?(e[t]=s[t],e):(e.variables||(e.variables={}),e.variables[t]=s[t],e)),{}),n=s.baseUrl||e.endpoint.DEFAULTS.baseUrl;return l.test(n)&&(r.url=n.replace(l,"/api/graphql")),e(r).then((e=>{if(e.data.errors){const t={};for(const i of Object.keys(e.headers))t[i]=e.headers[i];throw new o(r,t,e.data)}return e.data.data}))}(i,e,t)),{defaults:p.bind(null,i),endpoint:i.endpoint})}p(n.request,{headers:{"user-agent":`octokit-graphql.js/7.1.0 ${(0,s.getUserAgent)()}`},method:"POST",url:"/graphql"});const A=/^v1\./,u=/^ghs_/,d=/^ghu_/;async function h(e){const t=3===e.split(/\./).length,i=A.test(e)||u.test(e),s=d.test(e);return{type:"token",token:e,tokenType:t?"app":i?"installation":s?"user-to-server":"oauth"}}async function m(e,t,i,s){const r=t.endpoint.merge(i,s);return r.headers.authorization=function(e){return 3===e.split(/\./).length?`bearer ${e}`:`token ${e}`}(e),t(r)}const g=function(e){if(!e)throw new Error("[@octokit/auth-token] No token passed to createTokenAuth");if("string"!=typeof e)throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string");return e=e.replace(/^(token|bearer) +/i,""),Object.assign(h.bind(null,e),{hook:m.bind(null,e)})};var f="5.2.0",E=()=>{},C=console.warn.bind(console),y=console.error.bind(console),v=`octokit-core.js/${f} ${(0,s.getUserAgent)()}`,I=class{static{this.VERSION=f}static defaults(e){return class extends(this){constructor(...t){const i=t[0]||{};super("function"!=typeof e?Object.assign({},e,i,i.userAgent&&e.userAgent?{userAgent:`${i.userAgent} ${e.userAgent}`}:null):e(i))}}}static{this.plugins=[]}static plugin(...e){const t=this.plugins;return class extends(this){static{this.plugins=t.concat(e.filter((e=>!t.includes(e))))}}}constructor(e={}){const t=new r.Collection,i={baseUrl:n.request.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},e.request,{hook:t.bind(null,"request")}),mediaType:{previews:[],format:""}};var s;if(i.headers["user-agent"]=e.userAgent?`${e.userAgent} ${v}`:v,e.baseUrl&&(i.baseUrl=e.baseUrl),e.previews&&(i.mediaType.previews=e.previews),e.timeZone&&(i.headers["time-zone"]=e.timeZone),this.request=n.request.defaults(i),this.graphql=(s=this.request,p(s,{method:"POST",url:"/graphql"})).defaults(i),this.log=Object.assign({debug:E,info:E,warn:C,error:y},e.log),this.hook=t,e.authStrategy){const{authStrategy:i,...s}=e,r=i(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:s},e.auth));t.wrap("request",r.hook),this.auth=r}else if(e.auth){const i=g(e.auth);t.wrap("request",i.hook),this.auth=i}else this.auth=async()=>({type:"unauthenticated"});const o=this.constructor;for(let t=0;t{"use strict";function s(e){return"[object Object]"===Object.prototype.toString.call(e)}function r(e){var t,i;return!1!==s(e)&&(void 0===(t=e.constructor)||!1!==s(i=t.prototype)&&!1!==i.hasOwnProperty("isPrototypeOf"))}i.r(t),i.d(t,{GraphqlResponseError:()=>Qe,graphql:()=>_e,withCustomRequest:()=>Re});var n=i(21375);function o(e,t){const i=Object.assign({},e);return Object.keys(t).forEach((s=>{r(t[s])?s in e?i[s]=o(e[s],t[s]):Object.assign(i,{[s]:t[s]}):Object.assign(i,{[s]:t[s]})})),i}function a(e){for(const t in e)void 0===e[t]&&delete e[t];return e}function c(e,t,i){if("string"==typeof t){let[e,s]=t.split(" ");i=Object.assign(s?{method:e,url:s}:{url:e},i)}else i=Object.assign({},t);var s;i.headers=(s=i.headers)?Object.keys(s).reduce(((e,t)=>(e[t.toLowerCase()]=s[t],e)),{}):{},a(i),a(i.headers);const r=o(e||{},i);return e&&e.mediaType.previews.length&&(r.mediaType.previews=e.mediaType.previews.filter((e=>!r.mediaType.previews.includes(e))).concat(r.mediaType.previews)),r.mediaType.previews=r.mediaType.previews.map((e=>e.replace(/-preview/,""))),r}const l=/\{[^}]+\}/g;function p(e){return e.replace(/^\W+|\W+$/g,"").split(/,/)}function A(e,t){return Object.keys(e).filter((e=>!t.includes(e))).reduce(((t,i)=>(t[i]=e[i],t)),{})}function u(e){return e.split(/(%[0-9A-Fa-f]{2})/g).map((function(e){return/%[0-9A-Fa-f]/.test(e)||(e=encodeURI(e).replace(/%5B/g,"[").replace(/%5D/g,"]")),e})).join("")}function d(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function h(e,t,i){return t="+"===e||"#"===e?u(t):d(t),i?d(i)+"="+t:t}function m(e){return null!=e}function g(e){return";"===e||"&"===e||"?"===e}function f(e,t){var i=["+","#",".","/",";","?","&"];return e.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g,(function(e,s,r){if(s){let e="";const r=[];if(-1!==i.indexOf(s.charAt(0))&&(e=s.charAt(0),s=s.substr(1)),s.split(/,/g).forEach((function(i){var s=/([^:\*]*)(?::(\d+)|(\*))?/.exec(i);r.push(function(e,t,i,s){var r=e[i],n=[];if(m(r)&&""!==r)if("string"==typeof r||"number"==typeof r||"boolean"==typeof r)r=r.toString(),s&&"*"!==s&&(r=r.substring(0,parseInt(s,10))),n.push(h(t,r,g(t)?i:""));else if("*"===s)Array.isArray(r)?r.filter(m).forEach((function(e){n.push(h(t,e,g(t)?i:""))})):Object.keys(r).forEach((function(e){m(r[e])&&n.push(h(t,r[e],e))}));else{const e=[];Array.isArray(r)?r.filter(m).forEach((function(i){e.push(h(t,i))})):Object.keys(r).forEach((function(i){m(r[i])&&(e.push(d(i)),e.push(h(t,r[i].toString())))})),g(t)?n.push(d(i)+"="+e.join(",")):0!==e.length&&n.push(e.join(","))}else";"===t?m(r)&&n.push(d(i)):""!==r||"&"!==t&&"?"!==t?""===r&&n.push(""):n.push(d(i)+"=");return n}(t,e,s[1],s[2]||s[3]))})),e&&"+"!==e){var n=",";return"?"===e?n="&":"#"!==e&&(n=e),(0!==r.length?e:"")+r.join(n)}return r.join(",")}return u(r)}))}function E(e){let t,i=e.method.toUpperCase(),s=(e.url||"/").replace(/:([a-z]\w+)/g,"{$1}"),r=Object.assign({},e.headers),n=A(e,["method","baseUrl","url","headers","request","mediaType"]);const o=function(e){const t=e.match(l);return t?t.map(p).reduce(((e,t)=>e.concat(t)),[]):[]}(s);var a;s=(a=s,{expand:f.bind(null,a)}).expand(n),/^http/.test(s)||(s=e.baseUrl+s);const c=A(n,Object.keys(e).filter((e=>o.includes(e))).concat("baseUrl"));if(!/application\/octet-stream/i.test(r.accept)&&(e.mediaType.format&&(r.accept=r.accept.split(/,/).map((t=>t.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/,`application/vnd$1$2.${e.mediaType.format}`))).join(",")),e.mediaType.previews.length)){const t=r.accept.match(/[\w-]+(?=-preview)/g)||[];r.accept=t.concat(e.mediaType.previews).map((t=>`application/vnd.github.${t}-preview${e.mediaType.format?`.${e.mediaType.format}`:"+json"}`)).join(",")}return["GET","HEAD"].includes(i)?s=function(e,t){const i=/\?/.test(e)?"&":"?",s=Object.keys(t);return 0===s.length?e:e+i+s.map((e=>"q"===e?"q="+t.q.split("+").map(encodeURIComponent).join("+"):`${e}=${encodeURIComponent(t[e])}`)).join("&")}(s,c):"data"in c?t=c.data:Object.keys(c).length?t=c:r["content-length"]=0,r["content-type"]||void 0===t||(r["content-type"]="application/json; charset=utf-8"),["PATCH","PUT"].includes(i)&&void 0===t&&(t=""),Object.assign({method:i,url:s,headers:r},void 0!==t?{body:t}:null,e.request?{request:e.request}:null)}function C(e,t,i){return E(c(e,t,i))}const y=function e(t,i){const s=c(t,i),r=C.bind(null,s);return Object.assign(r,{DEFAULTS:s,defaults:e.bind(null,s),merge:c.bind(null,s),parse:E})}(null,{method:"GET",baseUrl:"https://api.github.com",headers:{accept:"application/vnd.github.v3+json","user-agent":`octokit-endpoint.js/6.0.12 ${(0,n.getUserAgent)()}`},mediaType:{format:"",previews:[]}});var v=i(12781),I=i(13685),B=i(57310),w=i(89897),b=i(95687),Q=i(59796);const x=v.Readable,k=Symbol("buffer"),D=Symbol("type");class S{constructor(){this[D]="";const e=arguments[0],t=arguments[1],i=[];let s=0;if(e){const t=e,r=Number(t.length);for(let e=0;e1&&void 0!==arguments[1]?arguments[1]:{},s=i.size;let r=void 0===s?0:s;var n=i.timeout;let o=void 0===n?0:n;null==e?e=null:O(e)?e=Buffer.from(e.toString()):M(e)||Buffer.isBuffer(e)||("[object ArrayBuffer]"===Object.prototype.toString.call(e)?e=Buffer.from(e):ArrayBuffer.isView(e)?e=Buffer.from(e.buffer,e.byteOffset,e.byteLength):e instanceof v||(e=Buffer.from(String(e)))),this[T]={body:e,disturbed:!1,error:null},this.size=r,this.timeout=o,e instanceof v&&e.on("error",(function(e){const i="AbortError"===e.name?e:new _(`Invalid response body while trying to fetch ${t.url}: ${e.message}`,"system",e);t[T].error=i}))}function L(){var e=this;if(this[T].disturbed)return N.Promise.reject(new TypeError(`body used already for: ${this.url}`));if(this[T].disturbed=!0,this[T].error)return N.Promise.reject(this[T].error);let t=this.body;if(null===t)return N.Promise.resolve(Buffer.alloc(0));if(M(t)&&(t=t.stream()),Buffer.isBuffer(t))return N.Promise.resolve(t);if(!(t instanceof v))return N.Promise.resolve(Buffer.alloc(0));let i=[],s=0,r=!1;return new N.Promise((function(n,o){let a;e.timeout&&(a=setTimeout((function(){r=!0,o(new _(`Response timeout while trying to fetch ${e.url} (over ${e.timeout}ms)`,"body-timeout"))}),e.timeout)),t.on("error",(function(t){"AbortError"===t.name?(r=!0,o(t)):o(new _(`Invalid response body while trying to fetch ${e.url}: ${t.message}`,"system",t))})),t.on("data",(function(t){if(!r&&null!==t){if(e.size&&s+t.length>e.size)return r=!0,void o(new _(`content size at ${e.url} over limit: ${e.size}`,"max-size"));s+=t.length,i.push(t)}})),t.on("end",(function(){if(!r){clearTimeout(a);try{n(Buffer.concat(i,s))}catch(t){o(new _(`Could not create Buffer from response body for ${e.url}: ${t.message}`,"system",t))}}}))}))}function O(e){return"object"==typeof e&&"function"==typeof e.append&&"function"==typeof e.delete&&"function"==typeof e.get&&"function"==typeof e.getAll&&"function"==typeof e.has&&"function"==typeof e.set&&("URLSearchParams"===e.constructor.name||"[object URLSearchParams]"===Object.prototype.toString.call(e)||"function"==typeof e.sort)}function M(e){return"object"==typeof e&&"function"==typeof e.arrayBuffer&&"string"==typeof e.type&&"function"==typeof e.stream&&"function"==typeof e.constructor&&"string"==typeof e.constructor.name&&/^(Blob|File)$/.test(e.constructor.name)&&/^(Blob|File)$/.test(e[Symbol.toStringTag])}function U(e){let t,i,s=e.body;if(e.bodyUsed)throw new Error("cannot clone body after it is used");return s instanceof v&&"function"!=typeof s.getBoundary&&(t=new F,i=new F,s.pipe(t),s.pipe(i),e[T].body=t,s=i),s}function P(e){return null===e?null:"string"==typeof e?"text/plain;charset=UTF-8":O(e)?"application/x-www-form-urlencoded;charset=UTF-8":M(e)?e.type||null:Buffer.isBuffer(e)||"[object ArrayBuffer]"===Object.prototype.toString.call(e)||ArrayBuffer.isView(e)?null:"function"==typeof e.getBoundary?`multipart/form-data;boundary=${e.getBoundary()}`:e instanceof v?null:"text/plain;charset=UTF-8"}function G(e){const t=e.body;return null===t?0:M(t)?t.size:Buffer.isBuffer(t)?t.length:t&&"function"==typeof t.getLengthSync&&(t._lengthRetrievers&&0==t._lengthRetrievers.length||t.hasKnownLength&&t.hasKnownLength())?t.getLengthSync():null}N.prototype={get body(){return this[T].body},get bodyUsed(){return this[T].disturbed},arrayBuffer(){return L.call(this).then((function(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}))},blob(){let e=this.headers&&this.headers.get("content-type")||"";return L.call(this).then((function(t){return Object.assign(new S([],{type:e.toLowerCase()}),{[k]:t})}))},json(){var e=this;return L.call(this).then((function(t){try{return JSON.parse(t.toString())}catch(t){return N.Promise.reject(new _(`invalid json response body at ${e.url} reason: ${t.message}`,"invalid-json"))}}))},text(){return L.call(this).then((function(e){return e.toString()}))},buffer(){return L.call(this)},textConverted(){var e=this;return L.call(this).then((function(t){return function(e,t){if("function"!=typeof R)throw new Error("The package `encoding` must be installed to use the textConverted() function");const i=t.get("content-type");let s,r,n="utf-8";return i&&(s=/charset=([^;]*)/i.exec(i)),r=e.slice(0,1024).toString(),!s&&r&&(s=/0&&void 0!==arguments[0]?arguments[0]:void 0;if(this[Y]=Object.create(null),e instanceof W){const t=e.raw(),i=Object.keys(t);for(const e of i)for(const i of t[e])this.append(e,i)}else if(null==e);else{if("object"!=typeof e)throw new TypeError("Provided initializer must be an object");{const t=e[Symbol.iterator];if(null!=t){if("function"!=typeof t)throw new TypeError("Header pairs must be iterable");const i=[];for(const t of e){if("object"!=typeof t||"function"!=typeof t[Symbol.iterator])throw new TypeError("Each header pair must be iterable");i.push(Array.from(t))}for(const e of i){if(2!==e.length)throw new TypeError("Each header pair must be a name/value tuple");this.append(e[0],e[1])}}else for(const t of Object.keys(e)){const i=e[t];this.append(t,i)}}}}get(e){H(e=`${e}`);const t=q(this[Y],e);return void 0===t?null:this[Y][t].join(", ")}forEach(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:void 0,i=z(this),s=0;for(;s1&&void 0!==arguments[1]?arguments[1]:"key+value";return Object.keys(e[Y]).sort().map("key"===t?function(e){return e.toLowerCase()}:"value"===t?function(t){return e[Y][t].join(", ")}:function(t){return[t.toLowerCase(),e[Y][t].join(", ")]})}W.prototype.entries=W.prototype[Symbol.iterator],Object.defineProperty(W.prototype,Symbol.toStringTag,{value:"Headers",writable:!1,enumerable:!1,configurable:!0}),Object.defineProperties(W.prototype,{get:{enumerable:!0},forEach:{enumerable:!0},set:{enumerable:!0},append:{enumerable:!0},has:{enumerable:!0},delete:{enumerable:!0},keys:{enumerable:!0},values:{enumerable:!0},entries:{enumerable:!0}});const $=Symbol("internal");function X(e,t){const i=Object.create(K);return i[$]={target:e,kind:t,index:0},i}const K=Object.setPrototypeOf({next(){if(!this||Object.getPrototypeOf(this)!==K)throw new TypeError("Value of `this` is not a HeadersIterator");var e=this[$];const t=e.target,i=e.kind,s=e.index,r=z(t,i);return s>=r.length?{value:void 0,done:!0}:(this[$].index=s+1,{value:r[s],done:!1})}},Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));function Z(e){const t=Object.assign({__proto__:null},e[Y]),i=q(e[Y],"Host");return void 0!==i&&(t[i]=t[i][0]),t}Object.defineProperty(K,Symbol.toStringTag,{value:"HeadersIterator",writable:!1,enumerable:!1,configurable:!0});const ee=Symbol("Response internals"),te=I.STATUS_CODES;class ie{constructor(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};N.call(this,e,t);const i=t.status||200,s=new W(t.headers);if(null!=e&&!s.has("Content-Type")){const t=P(e);t&&s.append("Content-Type",t)}this[ee]={url:t.url,status:i,statusText:t.statusText||te[i],headers:s,counter:t.counter}}get url(){return this[ee].url||""}get status(){return this[ee].status}get ok(){return this[ee].status>=200&&this[ee].status<300}get redirected(){return this[ee].counter>0}get statusText(){return this[ee].statusText}get headers(){return this[ee].headers}clone(){return new ie(U(this),{url:this.url,status:this.status,statusText:this.statusText,headers:this.headers,ok:this.ok,redirected:this.redirected})}}N.mixIn(ie.prototype),Object.defineProperties(ie.prototype,{url:{enumerable:!0},status:{enumerable:!0},ok:{enumerable:!0},redirected:{enumerable:!0},statusText:{enumerable:!0},headers:{enumerable:!0},clone:{enumerable:!0}}),Object.defineProperty(ie.prototype,Symbol.toStringTag,{value:"Response",writable:!1,enumerable:!1,configurable:!0});const se=Symbol("Request internals"),re=B.URL||w.URL,ne=B.parse,oe=B.format;function ae(e){return/^[a-zA-Z][a-zA-Z\d+\-.]*:/.exec(e)&&(e=new re(e).toString()),ne(e)}const ce="destroy"in v.Readable.prototype;function le(e){return"object"==typeof e&&"object"==typeof e[se]}class pe{constructor(e){let t,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};le(e)?t=ae(e.url):(t=e&&e.href?ae(e.href):ae(`${e}`),e={});let s=i.method||e.method||"GET";if(s=s.toUpperCase(),(null!=i.body||le(e)&&null!==e.body)&&("GET"===s||"HEAD"===s))throw new TypeError("Request with GET/HEAD method cannot have body");let r=null!=i.body?i.body:le(e)&&null!==e.body?U(e):null;N.call(this,r,{timeout:i.timeout||e.timeout||0,size:i.size||e.size||0});const n=new W(i.headers||e.headers||{});if(null!=r&&!n.has("Content-Type")){const e=P(r);e&&n.append("Content-Type",e)}let o=le(e)?e.signal:null;if("signal"in i&&(o=i.signal),null!=o&&!function(e){const t=e&&"object"==typeof e&&Object.getPrototypeOf(e);return!(!t||"AbortSignal"!==t.constructor.name)}(o))throw new TypeError("Expected signal to be an instanceof AbortSignal");this[se]={method:s,redirect:i.redirect||e.redirect||"follow",headers:n,parsedURL:t,signal:o},this.follow=void 0!==i.follow?i.follow:void 0!==e.follow?e.follow:20,this.compress=void 0!==i.compress?i.compress:void 0===e.compress||e.compress,this.counter=i.counter||e.counter||0,this.agent=i.agent||e.agent}get method(){return this[se].method}get url(){return oe(this[se].parsedURL)}get headers(){return this[se].headers}get redirect(){return this[se].redirect}get signal(){return this[se].signal}clone(){return new pe(this)}}function Ae(e){Error.call(this,e),this.type="aborted",this.message=e,Error.captureStackTrace(this,this.constructor)}N.mixIn(pe.prototype),Object.defineProperty(pe.prototype,Symbol.toStringTag,{value:"Request",writable:!1,enumerable:!1,configurable:!0}),Object.defineProperties(pe.prototype,{method:{enumerable:!0},url:{enumerable:!0},headers:{enumerable:!0},redirect:{enumerable:!0},clone:{enumerable:!0},signal:{enumerable:!0}}),Ae.prototype=Object.create(Error.prototype),Ae.prototype.constructor=Ae,Ae.prototype.name="AbortError";const ue=B.URL||w.URL,de=v.PassThrough;function he(e,t){if(!he.Promise)throw new Error("native promise missing, set fetch.Promise to your favorite alternative");return N.Promise=he.Promise,new he.Promise((function(i,s){const r=new pe(e,t),n=function(e){const t=e[se].parsedURL,i=new W(e[se].headers);if(i.has("Accept")||i.set("Accept","*/*"),!t.protocol||!t.hostname)throw new TypeError("Only absolute URLs are supported");if(!/^https?:$/.test(t.protocol))throw new TypeError("Only HTTP(S) protocols are supported");if(e.signal&&e.body instanceof v.Readable&&!ce)throw new Error("Cancellation of streamed requests with AbortSignal is not supported in node < 8");let s=null;if(null==e.body&&/^(POST|PUT)$/i.test(e.method)&&(s="0"),null!=e.body){const t=G(e);"number"==typeof t&&(s=String(t))}s&&i.set("Content-Length",s),i.has("User-Agent")||i.set("User-Agent","node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"),e.compress&&!i.has("Accept-Encoding")&&i.set("Accept-Encoding","gzip,deflate");let r=e.agent;return"function"==typeof r&&(r=r(t)),Object.assign({},t,{method:e.method,headers:Z(i),agent:r})}(r),o=("https:"===n.protocol?b:I).request,a=r.signal;let c=null;const l=function(){let e=new Ae("The user aborted a request.");s(e),r.body&&r.body instanceof v.Readable&&me(r.body,e),c&&c.body&&c.body.emit("error",e)};if(a&&a.aborted)return void l();const p=function(){l(),d()},A=o(n);let u;function d(){A.abort(),a&&a.removeEventListener("abort",p),clearTimeout(u)}a&&a.addEventListener("abort",p),r.timeout&&A.once("socket",(function(e){u=setTimeout((function(){s(new _(`network timeout at: ${r.url}`,"request-timeout")),d()}),r.timeout)})),A.on("error",(function(e){s(new _(`request to ${r.url} failed, reason: ${e.message}`,"system",e)),c&&c.body&&me(c.body,e),d()})),function(e,t){let i;e.on("socket",(function(e){i=e})),e.on("response",(function(e){const s=e.headers;"chunked"!==s["transfer-encoding"]||s["content-length"]||e.once("close",(function(e){if(i&&i.listenerCount("data")>0&&!e){const e=new Error("Premature close");e.code="ERR_STREAM_PREMATURE_CLOSE",t(e)}}))}))}(A,(function(e){a&&a.aborted||c&&c.body&&me(c.body,e)})),parseInt(process.version.substring(1))<14&&A.on("socket",(function(e){e.addListener("close",(function(t){const i=e.listenerCount("data")>0;if(c&&i&&!t&&(!a||!a.aborted)){const e=new Error("Premature close");e.code="ERR_STREAM_PREMATURE_CLOSE",c.body.emit("error",e)}}))})),A.on("response",(function(e){clearTimeout(u);const t=function(e){const t=new W;for(const i of Object.keys(e))if(!V.test(i))if(Array.isArray(e[i]))for(const s of e[i])j.test(s)||(void 0===t[Y][i]?t[Y][i]=[s]:t[Y][i].push(s));else j.test(e[i])||(t[Y][i]=[e[i]]);return t}(e.headers);if(he.isRedirect(e.statusCode)){const o=t.get("Location");let a=null;try{a=null===o?null:new ue(o,r.url).toString()}catch(e){if("manual"!==r.redirect)return s(new _(`uri requested responds with an invalid redirect URL: ${o}`,"invalid-redirect")),void d()}switch(r.redirect){case"error":return s(new _(`uri requested responds with a redirect, redirect mode is set to error: ${r.url}`,"no-redirect")),void d();case"manual":if(null!==a)try{t.set("Location",a)}catch(e){s(e)}break;case"follow":if(null===a)break;if(r.counter>=r.follow)return s(new _(`maximum redirect reached at: ${r.url}`,"max-redirect")),void d();const o={headers:new W(r.headers),follow:r.follow,counter:r.counter+1,agent:r.agent,compress:r.compress,method:r.method,body:r.body,signal:r.signal,timeout:r.timeout,size:r.size};if(!function(e,t){const i=new ue(t).hostname,s=new ue(e).hostname;return i===s||"."===i[i.length-s.length-1]&&i.endsWith(s)}(r.url,a)||(n=r.url,new ue(a).protocol!==new ue(n).protocol))for(const e of["authorization","www-authenticate","cookie","cookie2"])o.headers.delete(e);return 303!==e.statusCode&&r.body&&null===G(r)?(s(new _("Cannot follow redirect with body being a readable stream","unsupported-redirect")),void d()):(303!==e.statusCode&&(301!==e.statusCode&&302!==e.statusCode||"POST"!==r.method)||(o.method="GET",o.body=void 0,o.headers.delete("content-length")),i(he(new pe(a,o))),void d())}}var n;e.once("end",(function(){a&&a.removeEventListener("abort",p)}));let o=e.pipe(new de);const l={url:r.url,status:e.statusCode,statusText:e.statusMessage,headers:t,size:r.size,timeout:r.timeout,counter:r.counter},A=t.get("Content-Encoding");if(!r.compress||"HEAD"===r.method||null===A||204===e.statusCode||304===e.statusCode)return c=new ie(o,l),void i(c);const h={flush:Q.Z_SYNC_FLUSH,finishFlush:Q.Z_SYNC_FLUSH};if("gzip"==A||"x-gzip"==A)return o=o.pipe(Q.createGunzip(h)),c=new ie(o,l),void i(c);if("deflate"==A||"x-deflate"==A){const t=e.pipe(new de);return t.once("data",(function(e){o=8==(15&e[0])?o.pipe(Q.createInflate()):o.pipe(Q.createInflateRaw()),c=new ie(o,l),i(c)})),void t.on("end",(function(){c||(c=new ie(o,l),i(c))}))}if("br"==A&&"function"==typeof Q.createBrotliDecompress)return o=o.pipe(Q.createBrotliDecompress()),c=new ie(o,l),void i(c);c=new ie(o,l),i(c)})),function(e,t){const i=t.body;null===i?e.end():M(i)?i.stream().pipe(e):Buffer.isBuffer(i)?(e.write(i),e.end()):i.pipe(e)}(A,r)}))}function me(e,t){e.destroy?e.destroy(t):(e.emit("error",t),e.end())}he.isRedirect=function(e){return 301===e||302===e||303===e||307===e||308===e},he.Promise=global.Promise;const ge=he;var fe=i(57751),Ee=i(36219),Ce=i.n(Ee);const ye=Ce()((e=>console.warn(e))),ve=Ce()((e=>console.warn(e)));class Ie extends Error{constructor(e,t,i){let s;super(e),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name="HttpError",this.status=t,"headers"in i&&void 0!==i.headers&&(s=i.headers),"response"in i&&(this.response=i.response,s=i.response.headers);const r=Object.assign({},i.request);i.request.headers.authorization&&(r.headers=Object.assign({},i.request.headers,{authorization:i.request.headers.authorization.replace(/ .*$/," [REDACTED]")})),r.url=r.url.replace(/\bclient_secret=\w+/g,"client_secret=[REDACTED]").replace(/\baccess_token=\w+/g,"access_token=[REDACTED]"),this.request=r,Object.defineProperty(this,"code",{get:()=>(ye(new fe.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`.")),t)}),Object.defineProperty(this,"headers",{get:()=>(ve(new fe.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`.")),s||{})})}}function Be(e){const t=e.request&&e.request.log?e.request.log:console;(r(e.body)||Array.isArray(e.body))&&(e.body=JSON.stringify(e.body));let i,s,n={};return(e.request&&e.request.fetch||ge)(e.url,Object.assign({method:e.method,body:e.body,headers:e.headers,redirect:e.redirect},e.request)).then((async r=>{s=r.url,i=r.status;for(const e of r.headers)n[e[0]]=e[1];if("deprecation"in n){const i=n.link&&n.link.match(/<([^>]+)>; rel="deprecation"/),s=i&&i.pop();t.warn(`[@octokit/request] "${e.method} ${e.url}" is deprecated. It is scheduled to be removed on ${n.sunset}${s?`. See ${s}`:""}`)}if(204!==i&&205!==i){if("HEAD"===e.method){if(i<400)return;throw new Ie(r.statusText,i,{response:{url:s,status:i,headers:n,data:void 0},request:e})}if(304===i)throw new Ie("Not modified",i,{response:{url:s,status:i,headers:n,data:await we(r)},request:e});if(i>=400){const t=await we(r),o=new Ie(function(e){return"string"==typeof e?e:"message"in e?Array.isArray(e.errors)?`${e.message}: ${e.errors.map(JSON.stringify).join(", ")}`:e.message:`Unknown error: ${JSON.stringify(e)}`}(t),i,{response:{url:s,status:i,headers:n,data:t},request:e});throw o}return we(r)}})).then((e=>({status:i,url:s,headers:n,data:e}))).catch((t=>{if(t instanceof Ie)throw t;throw new Ie(t.message,500,{request:e})}))}async function we(e){const t=e.headers.get("content-type");return/application\/json/.test(t)?e.json():!t||/^text\/|charset=utf-8$/.test(t)?e.text():function(e){return e.arrayBuffer()}(e)}const be=function e(t,i){const s=t.defaults(i);return Object.assign((function(t,i){const r=s.merge(t,i);if(!r.request||!r.request.hook)return Be(s.parse(r));const n=(e,t)=>Be(s.parse(s.merge(e,t)));return Object.assign(n,{endpoint:s,defaults:e.bind(null,s)}),r.request.hook(n,r)}),{endpoint:s,defaults:e.bind(null,s)})}(y,{headers:{"user-agent":`octokit-request.js/5.6.3 ${(0,n.getUserAgent)()}`}});class Qe extends Error{constructor(e,t,i){super("Request failed due to following response errors:\n"+i.errors.map((e=>` - ${e.message}`)).join("\n")),this.request=e,this.headers=t,this.response=i,this.name="GraphqlResponseError",this.errors=i.errors,this.data=i.data,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}const xe=["method","baseUrl","url","headers","request","query","mediaType"],ke=["query","method","url"],De=/\/api\/v3\/?$/;function Se(e,t){const i=e.defaults(t);return Object.assign(((e,t)=>function(e,t,i){if(i){if("string"==typeof t&&"query"in i)return Promise.reject(new Error('[@octokit/graphql] "query" cannot be used as variable name'));for(const e in i)if(ke.includes(e))return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}const s="string"==typeof t?Object.assign({query:t},i):t,r=Object.keys(s).reduce(((e,t)=>xe.includes(t)?(e[t]=s[t],e):(e.variables||(e.variables={}),e.variables[t]=s[t],e)),{}),n=s.baseUrl||e.endpoint.DEFAULTS.baseUrl;return De.test(n)&&(r.url=n.replace(De,"/api/graphql")),e(r).then((e=>{if(e.data.errors){const t={};for(const i of Object.keys(e.headers))t[i]=e.headers[i];throw new Qe(r,t,e.data)}return e.data.data}))}(i,e,t)),{defaults:Se.bind(null,i),endpoint:be.endpoint})}const _e=Se(be,{headers:{"user-agent":`octokit-graphql.js/4.8.0 ${(0,n.getUserAgent)()}`},method:"POST",url:"/graphql"});function Re(e){return Se(e,{method:"POST",url:"/graphql"})}},32546:(e,t,i)=>{"use strict";var s,r=Object.create,n=Object.defineProperty,o=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,c=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,p=(e,t,i,s)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let r of a(t))l.call(e,r)||r===i||n(e,r,{get:()=>t[r],enumerable:!(s=o(t,r))||s.enumerable});return e},A=(e,t,i)=>(i=null!=e?r(c(e)):{},p(!t&&e&&e.__esModule?i:n(i,"default",{value:e,enumerable:!0}),e)),u={};((e,t)=>{for(var i in t)n(e,i,{get:t[i],enumerable:!0})})(u,{OAuthApp:()=>z,createAWSLambdaAPIGatewayV2Handler:()=>W,createNodeMiddleware:()=>q,createWebWorkerHandler:()=>Y,handleRequest:()=>H,sendNodeResponse:()=>J,unknownRouteResponse:()=>j}),e.exports=(s=u,p(n({},"__esModule",{value:!0}),s));var d=i(62419),h="6.1.0";function m(e,t,i){if(Array.isArray(t))for(const s of t)m(e,s,i);else e.eventHandlers[t]||(e.eventHandlers[t]=[]),e.eventHandlers[t].push(i)}var g=i(96049),f=i(21375),E=g.Octokit.defaults({userAgent:`octokit-oauth-app.js/${h} ${(0,f.getUserAgent)()}`}),C=i(3360);async function y(e,t){const{name:i,action:s}=t;if(e.eventHandlers[`${i}.${s}`])for(const r of e.eventHandlers[`${i}.${s}`])await r(t);if(e.eventHandlers[i])for(const s of e.eventHandlers[i])await s(t)}async function v(e,t){return e.octokit.auth({type:"oauth-user",...t,async factory(t){const i=new e.Octokit({authStrategy:C.createOAuthUserAuth,auth:t}),s=await i.auth({type:"get"});return await y(e,{name:"token",action:"created",token:s.token,scopes:s.scopes,authentication:s,octokit:i}),i}})}var I=A(i(11393));function B(e,t){const i={clientId:e.clientId,request:e.octokit.request,...t,allowSignup:e.allowSignup??t.allowSignup,redirectUrl:t.redirectUrl??e.redirectUrl,scopes:t.scopes??e.defaultScopes};return I.getWebFlowAuthorizationUrl({clientType:e.clientType,...i})}var w=A(i(62419));async function b(e,t){const i=await e.octokit.auth({type:"oauth-user",...t});return await y(e,{name:"token",action:"created",token:i.token,scopes:i.scopes,authentication:i,octokit:new e.Octokit({authStrategy:w.createOAuthUserAuth,auth:{clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:i.token,scopes:i.scopes,refreshToken:i.refreshToken,expiresAt:i.expiresAt,refreshTokenExpiresAt:i.refreshTokenExpiresAt}})}),{authentication:i}}var Q=A(i(11393));async function x(e,t){const i=await Q.checkToken({clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,request:e.octokit.request,...t});return Object.assign(i.authentication,{type:"token",tokenType:"oauth"}),i}var k=A(i(11393)),D=i(3360);async function S(e,t){const i={clientId:e.clientId,clientSecret:e.clientSecret,request:e.octokit.request,...t};if("oauth-app"===e.clientType){const t=await k.resetToken({clientType:"oauth-app",...i}),s=Object.assign(t.authentication,{type:"token",tokenType:"oauth"});return await y(e,{name:"token",action:"reset",token:t.authentication.token,scopes:t.authentication.scopes||void 0,authentication:s,octokit:new e.Octokit({authStrategy:D.createOAuthUserAuth,auth:{clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:t.authentication.token,scopes:t.authentication.scopes}})}),{...t,authentication:s}}const s=await k.resetToken({clientType:"github-app",...i}),r=Object.assign(s.authentication,{type:"token",tokenType:"oauth"});return await y(e,{name:"token",action:"reset",token:s.authentication.token,authentication:r,octokit:new e.Octokit({authStrategy:D.createOAuthUserAuth,auth:{clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:s.authentication.token}})}),{...s,authentication:r}}var _=A(i(11393)),R=i(3360);async function T(e,t){if("oauth-app"===e.clientType)throw new Error("[@octokit/oauth-app] app.refreshToken() is not supported for OAuth Apps");const i=await _.refreshToken({clientType:"github-app",clientId:e.clientId,clientSecret:e.clientSecret,request:e.octokit.request,refreshToken:t.refreshToken}),s=Object.assign(i.authentication,{type:"token",tokenType:"oauth"});return await y(e,{name:"token",action:"refreshed",token:i.authentication.token,authentication:s,octokit:new e.Octokit({authStrategy:R.createOAuthUserAuth,auth:{clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:i.authentication.token}})}),{...i,authentication:s}}var F=A(i(11393)),N=i(3360);async function L(e,t){if("oauth-app"===e.clientType)throw new Error("[@octokit/oauth-app] app.scopeToken() is not supported for OAuth Apps");const i=await F.scopeToken({clientType:"github-app",clientId:e.clientId,clientSecret:e.clientSecret,request:e.octokit.request,...t}),s=Object.assign(i.authentication,{type:"token",tokenType:"oauth"});return await y(e,{name:"token",action:"scoped",token:i.authentication.token,authentication:s,octokit:new e.Octokit({authStrategy:N.createOAuthUserAuth,auth:{clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:i.authentication.token}})}),{...i,authentication:s}}var O=A(i(11393)),M=i(37573);async function U(e,t){const i={clientId:e.clientId,clientSecret:e.clientSecret,request:e.octokit.request,...t},s="oauth-app"===e.clientType?await O.deleteToken({clientType:"oauth-app",...i}):await O.deleteToken({clientType:"github-app",...i});return await y(e,{name:"token",action:"deleted",token:t.token,octokit:new e.Octokit({authStrategy:M.createUnauthenticatedAuth,auth:{reason:'Handling "token.deleted" event. The access for the token has been revoked.'}})}),s}var P=A(i(11393)),G=i(37573);async function V(e,t){const i={clientId:e.clientId,clientSecret:e.clientSecret,request:e.octokit.request,...t},s="oauth-app"===e.clientType?await P.deleteAuthorization({clientType:"oauth-app",...i}):await P.deleteAuthorization({clientType:"github-app",...i});return await y(e,{name:"token",action:"deleted",token:t.token,octokit:new e.Octokit({authStrategy:G.createUnauthenticatedAuth,auth:{reason:'Handling "token.deleted" event. The access for the token has been revoked.'}})}),await y(e,{name:"authorization",action:"deleted",token:t.token,octokit:new e.Octokit({authStrategy:G.createUnauthenticatedAuth,auth:{reason:'Handling "authorization.deleted" event. The access for the app has been revoked.'}})}),s}function j(e){return{status:404,headers:{"content-type":"application/json"},text:JSON.stringify({error:`Unknown route: ${e.method} ${e.url}`})}}async function H(e,{pathPrefix:t="/api/github/oauth"},i){if("OPTIONS"===i.method)return{status:200,headers:{"access-control-allow-origin":"*","access-control-allow-methods":"*","access-control-allow-headers":"Content-Type, User-Agent, Authorization"}};let{pathname:s}=new URL(i.url,"http://localhost");if(!s.startsWith(`${t}/`))return;s=s.slice(t.length+1);const r=[i.method,s].join(" "),n={getLogin:"GET login",getCallback:"GET callback",createToken:"POST token",getToken:"GET token",patchToken:"PATCH token",patchRefreshToken:"PATCH refresh-token",scopeToken:"POST token/scoped",deleteToken:"DELETE token",deleteGrant:"DELETE grant"};if(!Object.values(n).includes(r))return j(i);let o;try{const e=await i.text();o=e?JSON.parse(e):{}}catch(e){return{status:400,headers:{"content-type":"application/json","access-control-allow-origin":"*"},text:JSON.stringify({error:"[@octokit/oauth-app] request error"})}}const{searchParams:a}=new URL(i.url,"http://localhost"),c=Object.fromEntries(a),l=i.headers;try{if(r===n.getLogin){const{url:t}=e.getWebFlowAuthorizationUrl({state:c.state,scopes:c.scopes?c.scopes.split(","):void 0,allowSignup:c.allowSignup?"true"===c.allowSignup:void 0,redirectUrl:c.redirectUrl});return{status:302,headers:{location:t}}}if(r===n.getCallback){if(c.error)throw new Error(`[@octokit/oauth-app] ${c.error} ${c.error_description}`);if(!c.code)throw new Error('[@octokit/oauth-app] "code" parameter is required');const{authentication:{token:t}}=await e.createToken({code:c.code});return{status:200,headers:{"content-type":"text/html"},text:`

Token created successfully

\n\n

Your token is: ${t}. Copy it now as it cannot be shown again.

`}}if(r===n.createToken){const{code:t,redirectUrl:i}=o;if(!t)throw new Error('[@octokit/oauth-app] "code" parameter is required');const s=await e.createToken({code:t,redirectUrl:i});return delete s.authentication.clientSecret,{status:201,headers:{"content-type":"application/json","access-control-allow-origin":"*"},text:JSON.stringify(s)}}if(r===n.getToken){const t=l.authorization?.substr(6);if(!t)throw new Error('[@octokit/oauth-app] "Authorization" header is required');const i=await e.checkToken({token:t});return delete i.authentication.clientSecret,{status:200,headers:{"content-type":"application/json","access-control-allow-origin":"*"},text:JSON.stringify(i)}}if(r===n.patchToken){const t=l.authorization?.substr(6);if(!t)throw new Error('[@octokit/oauth-app] "Authorization" header is required');const i=await e.resetToken({token:t});return delete i.authentication.clientSecret,{status:200,headers:{"content-type":"application/json","access-control-allow-origin":"*"},text:JSON.stringify(i)}}if(r===n.patchRefreshToken){const t=l.authorization?.substr(6);if(!t)throw new Error('[@octokit/oauth-app] "Authorization" header is required');const{refreshToken:i}=o;if(!i)throw new Error("[@octokit/oauth-app] refreshToken must be sent in request body");const s=await e.refreshToken({refreshToken:i});return delete s.authentication.clientSecret,{status:200,headers:{"content-type":"application/json","access-control-allow-origin":"*"},text:JSON.stringify(s)}}if(r===n.scopeToken){const t=l.authorization?.substr(6);if(!t)throw new Error('[@octokit/oauth-app] "Authorization" header is required');const i=await e.scopeToken({token:t,...o});return delete i.authentication.clientSecret,{status:200,headers:{"content-type":"application/json","access-control-allow-origin":"*"},text:JSON.stringify(i)}}if(r===n.deleteToken){const t=l.authorization?.substr(6);if(!t)throw new Error('[@octokit/oauth-app] "Authorization" header is required');return await e.deleteToken({token:t}),{status:204,headers:{"access-control-allow-origin":"*"}}}const t=l.authorization?.substr(6);if(!t)throw new Error('[@octokit/oauth-app] "Authorization" header is required');return await e.deleteAuthorization({token:t}),{status:204,headers:{"access-control-allow-origin":"*"}}}catch(e){return{status:400,headers:{"content-type":"application/json","access-control-allow-origin":"*"},text:JSON.stringify({error:e.message})}}}function J(e,t){t.writeHead(e.status,e.headers),t.end(e.text)}function q(e,t={}){return async function(i,s,r){const n=await function(e){const{method:t,url:i,headers:s}=e;return{method:t,url:i,headers:s,text:async function(){return await new Promise(((t,i)=>{let s=[];e.on("error",i).on("data",(e=>s.push(e))).on("end",(()=>t(Buffer.concat(s).toString())))}))}}}(i),o=await H(e,t,n);return o?(J(o,s),!0):(r?.(),!1)}}function Y(e,t={}){return async function(i){const s=await function(e){const t=Object.fromEntries(e.headers.entries());return{method:e.method,url:e.url,headers:t,text:()=>e.text()}}(i),r=await H(e,t,s);return r?function(e){return new Response(e.text,{status:e.status,headers:e.headers})}(r):void 0}}function W(e,t={}){return async function(i){const s=function(e){const{method:t}=e.requestContext.http;let i=e.rawPath;const{stage:s}=e.requestContext;return i.startsWith("/"+s)&&(i=i.substring(s.length+1)),e.rawQueryString&&(i+="?"+e.rawQueryString),{method:t,url:i,headers:e.headers,text:async()=>e.body||""}}(i),r=await H(e,t,s);return r?{statusCode:(n=r).status,headers:n.headers,body:n.text}:void 0;var n}}var z=class{static{this.VERSION=h}static defaults(e){return class extends(this){constructor(...t){super({...e,...t[0]})}}}constructor(e){const t=e.Octokit||E;this.type=e.clientType||"oauth-app";const i=new t({authStrategy:d.createOAuthAppAuth,auth:{clientType:this.type,clientId:e.clientId,clientSecret:e.clientSecret}}),s={clientType:this.type,clientId:e.clientId,clientSecret:e.clientSecret,defaultScopes:e.defaultScopes||[],allowSignup:e.allowSignup,baseUrl:e.baseUrl,redirectUrl:e.redirectUrl,log:e.log,Octokit:t,octokit:i,eventHandlers:{}};this.on=m.bind(null,s),this.octokit=i,this.getUserOctokit=v.bind(null,s),this.getWebFlowAuthorizationUrl=B.bind(null,s),this.createToken=b.bind(null,s),this.checkToken=x.bind(null,s),this.resetToken=S.bind(null,s),this.refreshToken=T.bind(null,s),this.scopeToken=L.bind(null,s),this.deleteToken=U.bind(null,s),this.deleteAuthorization=V.bind(null,s)}}},4923:(e,t,i)=>{"use strict";i.d(t,{a:()=>o});var s=i(65683),r=i(96756),n=i.n(r);async function o(e){const t=e.request||s.request,i=await t("POST /applications/{client_id}/token",{headers:{authorization:`basic ${n()(`${e.clientId}:${e.clientSecret}`)}`},client_id:e.clientId,access_token:e.token}),r={clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:e.token,scopes:i.data.scopes};return i.data.expires_at&&(r.expiresAt=i.data.expires_at),"github-app"===e.clientType&&delete r.scopes,{...i,authentication:r}}},63855:(e,t,i)=>{"use strict";i.d(t,{T:()=>n});var s=i(65683),r=i(21216);async function n(e){const t=e.request||s.request,i={client_id:e.clientId};return"scopes"in e&&Array.isArray(e.scopes)&&(i.scope=e.scopes.join(" ")),(0,r.d)(t,"POST /login/device/code",i)}},62616:(e,t,i)=>{"use strict";i.d(t,{s:()=>o});var s=i(65683),r=i(96756),n=i.n(r);async function o(e){return(e.request||s.request)("DELETE /applications/{client_id}/grant",{headers:{authorization:`basic ${n()(`${e.clientId}:${e.clientSecret}`)}`},client_id:e.clientId,access_token:e.token})}},46886:(e,t,i)=>{"use strict";i.d(t,{p:()=>o});var s=i(65683),r=i(96756),n=i.n(r);async function o(e){return(e.request||s.request)("DELETE /applications/{client_id}/token",{headers:{authorization:`basic ${n()(`${e.clientId}:${e.clientSecret}`)}`},client_id:e.clientId,access_token:e.token})}},85579:(e,t,i)=>{"use strict";i.d(t,{i:()=>n});var s=i(65683),r=i(21216);async function n(e){const t=e.request||s.request,i=await(0,r.d)(t,"POST /login/oauth/access_token",{client_id:e.clientId,device_code:e.code,grant_type:"urn:ietf:params:oauth:grant-type:device_code"}),n={clientType:e.clientType,clientId:e.clientId,token:i.data.access_token,scopes:i.data.scope.split(/\s+/).filter(Boolean)};if("clientSecret"in e&&(n.clientSecret=e.clientSecret),"github-app"===e.clientType){if("refresh_token"in i.data){const e=new Date(i.headers.date).getTime();n.refreshToken=i.data.refresh_token,n.expiresAt=o(e,i.data.expires_in),n.refreshTokenExpiresAt=o(e,i.data.refresh_token_expires_in)}delete n.scopes}return{...i,authentication:n}}function o(e,t){return new Date(e+1e3*t).toISOString()}},71060:(e,t,i)=>{"use strict";i.d(t,{y:()=>n});var s=i(65683),r=i(21216);async function n(e){const t=e.request||s.request,i=await(0,r.d)(t,"POST /login/oauth/access_token",{client_id:e.clientId,client_secret:e.clientSecret,code:e.code,redirect_uri:e.redirectUrl}),n={clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:i.data.access_token,scopes:i.data.scope.split(/\s+/).filter(Boolean)};if("github-app"===e.clientType){if("refresh_token"in i.data){const e=new Date(i.headers.date).getTime();n.refreshToken=i.data.refresh_token,n.expiresAt=o(e,i.data.expires_in),n.refreshTokenExpiresAt=o(e,i.data.refresh_token_expires_in)}delete n.scopes}return{...i,authentication:n}}function o(e,t){return new Date(e+1e3*t).toISOString()}},11393:(e,t,i)=>{"use strict";i.r(t),i.d(t,{VERSION:()=>s,checkToken:()=>p.a,createDeviceCode:()=>c.T,deleteAuthorization:()=>f.s,deleteToken:()=>g.p,exchangeDeviceCode:()=>l.i,exchangeWebFlowCode:()=>a.y,getWebFlowAuthorizationUrl:()=>o,refreshToken:()=>A.g,resetToken:()=>m.E,scopeToken:()=>h});const s="4.1.0";var r=i(65683),n=i(21216);function o({request:e=r.request,...t}){return function(e){const t=e.clientType||"oauth-app",i=e.baseUrl||"https://github.com",s={clientType:t,allowSignup:!1!==e.allowSignup,clientId:e.clientId,login:e.login||null,redirectUrl:e.redirectUrl||null,state:e.state||Math.random().toString(36).substr(2),url:""};if("oauth-app"===t){const t="scopes"in e?e.scopes:[];s.scopes="string"==typeof t?t.split(/[,\s]+/).filter(Boolean):t}return s.url=function(e,t){const i={allowSignup:"allow_signup",clientId:"client_id",login:"login",redirectUrl:"redirect_uri",scopes:"scope",state:"state"};let s=e;return Object.keys(i).filter((e=>null!==t[e])).filter((e=>"scopes"!==e||"github-app"!==t.clientType&&(!Array.isArray(t[e])||t[e].length>0))).map((e=>[i[e],`${t[e]}`])).forEach((([e,t],i)=>{s+=0===i?"?":"&",s+=`${e}=${encodeURIComponent(t)}`})),s}(`${i}/login/oauth/authorize`,s),s}({...t,baseUrl:(0,n.l)(e)})}var a=i(71060),c=i(63855),l=i(85579),p=i(4923),A=i(27550),u=i(96756),d=i.n(u);async function h(e){const{request:t,clientType:i,clientId:s,clientSecret:n,token:o,...a}=e,c=t||r.request,l=await c("POST /applications/{client_id}/token/scoped",{headers:{authorization:`basic ${d()(`${s}:${n}`)}`},client_id:s,access_token:o,...a}),p=Object.assign({clientType:i,clientId:s,clientSecret:n,token:l.data.token},l.data.expires_at?{expiresAt:l.data.expires_at}:{});return{...l,authentication:p}}var m=i(9147),g=i(46886),f=i(62616)},27550:(e,t,i)=>{"use strict";i.d(t,{g:()=>n});var s=i(65683),r=i(21216);async function n(e){const t=e.request||s.request,i=await(0,r.d)(t,"POST /login/oauth/access_token",{client_id:e.clientId,client_secret:e.clientSecret,grant_type:"refresh_token",refresh_token:e.refreshToken}),n=new Date(i.headers.date).getTime(),a={clientType:"github-app",clientId:e.clientId,clientSecret:e.clientSecret,token:i.data.access_token,refreshToken:i.data.refresh_token,expiresAt:o(n,i.data.expires_in),refreshTokenExpiresAt:o(n,i.data.refresh_token_expires_in)};return{...i,authentication:a}}function o(e,t){return new Date(e+1e3*t).toISOString()}},9147:(e,t,i)=>{"use strict";i.d(t,{E:()=>o});var s=i(65683),r=i(96756),n=i.n(r);async function o(e){const t=e.request||s.request,i=n()(`${e.clientId}:${e.clientSecret}`),r=await t("PATCH /applications/{client_id}/token",{headers:{authorization:`basic ${i}`},client_id:e.clientId,access_token:e.token}),o={clientType:e.clientType,clientId:e.clientId,clientSecret:e.clientSecret,token:r.data.token,scopes:r.data.scopes};return r.data.expires_at&&(o.expiresAt=r.data.expires_at),"github-app"===e.clientType&&delete o.scopes,{...r,authentication:o}}},21216:(e,t,i)=>{"use strict";i.d(t,{d:()=>n,l:()=>r});var s=i(98838);function r(e){const t=e.endpoint.DEFAULTS;return/^https:\/\/(api\.)?github\.com$/.test(t.baseUrl)?"https://github.com":t.baseUrl.replace("/api/v3","")}async function n(e,t,i){const n={baseUrl:r(e),headers:{accept:"application/json"},...i},o=await e(t,n);if("error"in o.data){const i=new s.RequestError(`${o.data.error_description} (${o.data.error}, ${o.data.error_uri})`,400,{request:e.endpoint.merge(t,n),headers:o.headers});throw i.response=o,i}return o}},98838:(e,t,i)=>{"use strict";i.r(t),i.d(t,{RequestError:()=>c});var s=i(57751),r=i(36219),n=i.n(r);const o=n()((e=>console.warn(e))),a=n()((e=>console.warn(e)));class c extends Error{constructor(e,t,i){let r;super(e),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name="HttpError",this.status=t,"headers"in i&&void 0!==i.headers&&(r=i.headers),"response"in i&&(this.response=i.response,r=i.response.headers);const n=Object.assign({},i.request);i.request.headers.authorization&&(n.headers=Object.assign({},i.request.headers,{authorization:i.request.headers.authorization.replace(/ .*$/," [REDACTED]")})),n.url=n.url.replace(/\bclient_secret=\w+/g,"client_secret=[REDACTED]").replace(/\baccess_token=\w+/g,"access_token=[REDACTED]"),this.request=n,Object.defineProperty(this,"code",{get:()=>(o(new s.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`.")),t)}),Object.defineProperty(this,"headers",{get:()=>(a(new s.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`.")),r||{})})}}},65683:(e,t,i)=>{"use strict";function s(e,t){const i=Object.assign({},e);return Object.keys(t).forEach((r=>{!function(e){if("object"!=typeof e||null===e)return!1;if("[object Object]"!==Object.prototype.toString.call(e))return!1;const t=Object.getPrototypeOf(e);if(null===t)return!0;const i=Object.prototype.hasOwnProperty.call(t,"constructor")&&t.constructor;return"function"==typeof i&&i instanceof i&&Function.prototype.call(i)===Function.prototype.call(e)}(t[r])?Object.assign(i,{[r]:t[r]}):r in e?i[r]=s(e[r],t[r]):Object.assign(i,{[r]:t[r]})})),i}function r(e){for(const t in e)void 0===e[t]&&delete e[t];return e}function n(e,t,i){if("string"==typeof t){let[e,s]=t.split(" ");i=Object.assign(s?{method:e,url:s}:{url:e},i)}else i=Object.assign({},t);var n;i.headers=(n=i.headers)?Object.keys(n).reduce(((e,t)=>(e[t.toLowerCase()]=n[t],e)),{}):{},r(i),r(i.headers);const o=s(e||{},i);return"/graphql"===i.url&&(e&&e.mediaType.previews?.length&&(o.mediaType.previews=e.mediaType.previews.filter((e=>!o.mediaType.previews.includes(e))).concat(o.mediaType.previews)),o.mediaType.previews=(o.mediaType.previews||[]).map((e=>e.replace(/-preview/,"")))),o}i.r(t),i.d(t,{request:()=>I});const o=/\{[^}]+\}/g;function a(e){return e.replace(/^\W+|\W+$/g,"").split(/,/)}function c(e,t){const i={__proto__:null};for(const s of Object.keys(e))-1===t.indexOf(s)&&(i[s]=e[s]);return i}function l(e){return e.split(/(%[0-9A-Fa-f]{2})/g).map((function(e){return/%[0-9A-Fa-f]/.test(e)||(e=encodeURI(e).replace(/%5B/g,"[").replace(/%5D/g,"]")),e})).join("")}function p(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function A(e,t,i){return t="+"===e||"#"===e?l(t):p(t),i?p(i)+"="+t:t}function u(e){return null!=e}function d(e){return";"===e||"&"===e||"?"===e}function h(e,t){var i=["+","#",".","/",";","?","&"];return e=e.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g,(function(e,s,r){if(s){let e="";const r=[];if(-1!==i.indexOf(s.charAt(0))&&(e=s.charAt(0),s=s.substr(1)),s.split(/,/g).forEach((function(i){var s=/([^:\*]*)(?::(\d+)|(\*))?/.exec(i);r.push(function(e,t,i,s){var r=e[i],n=[];if(u(r)&&""!==r)if("string"==typeof r||"number"==typeof r||"boolean"==typeof r)r=r.toString(),s&&"*"!==s&&(r=r.substring(0,parseInt(s,10))),n.push(A(t,r,d(t)?i:""));else if("*"===s)Array.isArray(r)?r.filter(u).forEach((function(e){n.push(A(t,e,d(t)?i:""))})):Object.keys(r).forEach((function(e){u(r[e])&&n.push(A(t,r[e],e))}));else{const e=[];Array.isArray(r)?r.filter(u).forEach((function(i){e.push(A(t,i))})):Object.keys(r).forEach((function(i){u(r[i])&&(e.push(p(i)),e.push(A(t,r[i].toString())))})),d(t)?n.push(p(i)+"="+e.join(",")):0!==e.length&&n.push(e.join(","))}else";"===t?u(r)&&n.push(p(i)):""!==r||"&"!==t&&"?"!==t?""===r&&n.push(""):n.push(p(i)+"=");return n}(t,e,s[1],s[2]||s[3]))})),e&&"+"!==e){var n=",";return"?"===e?n="&":"#"!==e&&(n=e),(0!==r.length?e:"")+r.join(n)}return r.join(",")}return l(r)})),"/"===e?e:e.replace(/\/$/,"")}function m(e){let t,i=e.method.toUpperCase(),s=(e.url||"/").replace(/:([a-z]\w+)/g,"{$1}"),r=Object.assign({},e.headers),n=c(e,["method","baseUrl","url","headers","request","mediaType"]);const l=function(e){const t=e.match(o);return t?t.map(a).reduce(((e,t)=>e.concat(t)),[]):[]}(s);var p;s=(p=s,{expand:h.bind(null,p)}).expand(n),/^http/.test(s)||(s=e.baseUrl+s);const A=c(n,Object.keys(e).filter((e=>l.includes(e))).concat("baseUrl"));if(!/application\/octet-stream/i.test(r.accept)&&(e.mediaType.format&&(r.accept=r.accept.split(/,/).map((t=>t.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/,`application/vnd$1$2.${e.mediaType.format}`))).join(",")),s.endsWith("/graphql")&&e.mediaType.previews?.length)){const t=r.accept.match(/[\w-]+(?=-preview)/g)||[];r.accept=t.concat(e.mediaType.previews).map((t=>`application/vnd.github.${t}-preview${e.mediaType.format?`.${e.mediaType.format}`:"+json"}`)).join(",")}return["GET","HEAD"].includes(i)?s=function(e,t){const i=/\?/.test(e)?"&":"?",s=Object.keys(t);return 0===s.length?e:e+i+s.map((e=>"q"===e?"q="+t.q.split("+").map(encodeURIComponent).join("+"):`${e}=${encodeURIComponent(t[e])}`)).join("&")}(s,A):"data"in A?t=A.data:Object.keys(A).length&&(t=A),r["content-type"]||void 0===t||(r["content-type"]="application/json; charset=utf-8"),["PATCH","PUT"].includes(i)&&void 0===t&&(t=""),Object.assign({method:i,url:s,headers:r},void 0!==t?{body:t}:null,e.request?{request:e.request}:null)}function g(e,t,i){return m(n(e,t,i))}var f=i(21375);const E=function e(t,i){const s=n(t,i),r=g.bind(null,s);return Object.assign(r,{DEFAULTS:s,defaults:e.bind(null,s),merge:n.bind(null,s),parse:m})}(null,{method:"GET",baseUrl:"https://api.github.com",headers:{accept:"application/vnd.github.v3+json","user-agent":`octokit-endpoint.js/9.0.5 ${(0,f.getUserAgent)()}`},mediaType:{format:""}});var C=i(98838);function y(e){const t=e.request&&e.request.log?e.request.log:console,i=!1!==e.request?.parseSuccessResponseBody;(function(e){if("object"!=typeof e||null===e)return!1;if("[object Object]"!==Object.prototype.toString.call(e))return!1;const t=Object.getPrototypeOf(e);if(null===t)return!0;const i=Object.prototype.hasOwnProperty.call(t,"constructor")&&t.constructor;return"function"==typeof i&&i instanceof i&&Function.prototype.call(i)===Function.prototype.call(e)}(e.body)||Array.isArray(e.body))&&(e.body=JSON.stringify(e.body));let s,r,n={},{fetch:o}=globalThis;if(e.request?.fetch&&(o=e.request.fetch),!o)throw new Error("fetch is not set. Please pass a fetch implementation as new Octokit({ request: { fetch }}). Learn more at https://github.com/octokit/octokit.js/#fetch-missing");return o(e.url,{method:e.method,body:e.body,redirect:e.request?.redirect,headers:e.headers,signal:e.request?.signal,...e.body&&{duplex:"half"}}).then((async o=>{r=o.url,s=o.status;for(const e of o.headers)n[e[0]]=e[1];if("deprecation"in n){const i=n.link&&n.link.match(/<([^>]+)>; rel="deprecation"/),s=i&&i.pop();t.warn(`[@octokit/request] "${e.method} ${e.url}" is deprecated. It is scheduled to be removed on ${n.sunset}${s?`. See ${s}`:""}`)}if(204!==s&&205!==s){if("HEAD"===e.method){if(s<400)return;throw new C.RequestError(o.statusText,s,{response:{url:r,status:s,headers:n,data:void 0},request:e})}if(304===s)throw new C.RequestError("Not modified",s,{response:{url:r,status:s,headers:n,data:await v(o)},request:e});if(s>=400){const t=await v(o),i=new C.RequestError(function(e){if("string"==typeof e)return e;let t;return t="documentation_url"in e?` - ${e.documentation_url}`:"","message"in e?Array.isArray(e.errors)?`${e.message}: ${e.errors.map(JSON.stringify).join(", ")}${t}`:`${e.message}${t}`:`Unknown error: ${JSON.stringify(e)}`}(t),s,{response:{url:r,status:s,headers:n,data:t},request:e});throw i}return i?await v(o):o.body}})).then((e=>({status:s,url:r,headers:n,data:e}))).catch((t=>{if(t instanceof C.RequestError)throw t;if("AbortError"===t.name)throw t;let i=t.message;throw"TypeError"===t.name&&"cause"in t&&(t.cause instanceof Error?i=t.cause.message:"string"==typeof t.cause&&(i=t.cause)),new C.RequestError(i,500,{request:e})}))}async function v(e){const t=e.headers.get("content-type");return/application\/json/.test(t)?e.json().catch((()=>e.text())).catch((()=>"")):!t||/^text\/|charset=utf-8$/.test(t)?e.text():function(e){return e.arrayBuffer()}(e)}const I=function e(t,i){const s=t.defaults(i);return Object.assign((function(t,i){const r=s.merge(t,i);if(!r.request||!r.request.hook)return y(s.parse(r));const n=(e,t)=>y(s.parse(s.merge(e,t)));return Object.assign(n,{endpoint:s,defaults:e.bind(null,s)}),r.request.hook(n,r)}),{endpoint:s,defaults:e.bind(null,s)})}(E,{headers:{"user-agent":`octokit-request.js/8.4.0 ${(0,f.getUserAgent)()}`}})},94832:(e,t)=>{"use strict";var i;Object.defineProperty(t,"__esModule",{value:!0}),t.ConsoleLogger=t.LogLevel=void 0,function(e){e.ERROR="error",e.WARN="warn",e.INFO="info",e.DEBUG="debug"}(i=t.LogLevel||(t.LogLevel={}));class s{constructor(){this.level=i.INFO,this.name=""}getLevel(){return this.level}setLevel(e){this.level=e}setName(e){this.name=e}debug(...e){s.isMoreOrEqualSevere(i.DEBUG,this.level)&&console.debug(s.labels.get(i.DEBUG),this.name,...e)}info(...e){s.isMoreOrEqualSevere(i.INFO,this.level)&&console.info(s.labels.get(i.INFO),this.name,...e)}warn(...e){s.isMoreOrEqualSevere(i.WARN,this.level)&&console.warn(s.labels.get(i.WARN),this.name,...e)}error(...e){s.isMoreOrEqualSevere(i.ERROR,this.level)&&console.error(s.labels.get(i.ERROR),this.name,...e)}static isMoreOrEqualSevere(e,t){return s.severity[e]>=s.severity[t]}}t.ConsoleLogger=s,s.labels=(()=>{const e=Object.entries(i).map((([e,t])=>[t,`[${e}] `]));return new Map(e)})(),s.severity={[i.ERROR]:400,[i.WARN]:300,[i.INFO]:200,[i.DEBUG]:100}},73247:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},69134:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},8702:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},52866:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},91939:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},92523:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},17578:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i);var r=Object.getOwnPropertyDescriptor(t,i);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[i]}}),Object.defineProperty(e,s,r)}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__exportStar||function(e,t){for(var i in e)"default"===i||Object.prototype.hasOwnProperty.call(t,i)||s(t,e,i)};Object.defineProperty(t,"__esModule",{value:!0}),r(i(91939),t),r(i(92523),t),r(i(33144),t),r(i(88851),t),r(i(69700),t),r(i(69134),t),r(i(8702),t),r(i(73247),t),r(i(52866),t)},88851:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},33144:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},69700:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},11055:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i);var r=Object.getOwnPropertyDescriptor(t,i);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[i]}}),Object.defineProperty(e,s,r)}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.prototype.hasOwnProperty.call(e,i)&&s(t,e,i);return r(t,e),t},o=this&&this.__await||function(e){return this instanceof o?(this.v=e,this):new o(e)},a=this&&this.__asyncGenerator||function(e,t,i){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var s,r=i.apply(e,t||[]),n=[];return s={},a("next"),a("throw"),a("return"),s[Symbol.asyncIterator]=function(){return this},s;function a(e){r[e]&&(s[e]=function(t){return new Promise((function(i,s){n.push([e,t,i,s])>1||c(e,t)}))})}function c(e,t){try{(i=r[e](t)).value instanceof o?Promise.resolve(i.value.v).then(l,p):A(n[0][2],i)}catch(e){A(n[0][3],e)}var i}function l(e){c("next",e)}function p(e){c("throw",e)}function A(e,t){e(t),n.shift(),n.length&&c(n[0][0],n[0][1])}},c=this&&this.__asyncValues||function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,i=e[Symbol.asyncIterator];return i?i.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},s("next"),s("throw"),s("return"),t[Symbol.asyncIterator]=function(){return this},t);function s(i){t[i]=e[i]&&function(t){return new Promise((function(s,r){!function(e,t,i,s){Promise.resolve(s).then((function(t){e({value:t,done:i})}),t)}(s,r,(t=e[i](t)).done,t.value)}))}}},l=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.buildThreadTsWarningMessage=t.WebClient=t.WebClientEvent=void 0;const p=i(63477),A=i(71017),u=l(i(59796)),d=i(73837),h=l(i(42412)),m=l(i(88464)),g=n(i(32656)),f=l(i(34425)),E=l(i(90504)),C=l(i(30547)),y=i(25242),v=i(57390),I=i(47056),B=i(94139),w=i(39847),b=l(i(83313)),Q=i(28666),x=()=>{};var k;!function(e){e.RATE_LIMITED="rate_limited"}(k=t.WebClientEvent||(t.WebClientEvent={}));class D extends y.Methods{constructor(e,{slackApiUrl:t="https://slack.com/api/",logger:i,logLevel:s,maxRequestConcurrency:r=100,retryConfig:n=w.tenRetriesInAboutThirtyMinutes,agent:o,tls:a,timeout:c=0,rejectRateLimitedCalls:l=!1,headers:p={},teamId:A}={}){super(),this.token=e,this.slackApiUrl=t,this.retryConfig=n,this.requestQueue=new m.default({concurrency:r}),this.tlsConfig=void 0!==a?a:{},this.rejectRateLimitedCalls=l,this.teamId=A,void 0!==i?(this.logger=i,void 0!==s&&this.logger.debug("The logLevel given to WebClient was ignored as you also gave logger")):this.logger=(0,B.getLogger)(D.loggerName,null!=s?s:B.LogLevel.INFO,i),this.token&&!p.Authorization&&(p.Authorization=`Bearer ${this.token}`),this.axios=f.default.create({timeout:c,baseURL:t,headers:(0,C.default)()?p:Object.assign({"User-Agent":(0,v.getUserAgent)()},p),httpAgent:o,httpsAgent:o,transformRequest:[this.serializeApiCallOptions.bind(this)],validateStatus:()=>!0,maxRedirects:0,proxy:!1}),delete this.axios.defaults.headers.post["Content-Type"],this.logger.debug("initialized")}async apiCall(e,t={}){if(this.logger.debug(`apiCall('${e}') start`),function(e,t){const i=["channels.","groups.","im.","mpim."].some((t=>new RegExp(`^${t}`).test(e))),s=["admin.conversations.whitelist.","stars."].some((t=>new RegExp(`^${t}`).test(e)));i?t.warn(`${e} is deprecated. Please use the Conversations API instead. For more info, go to https://api.slack.com/changelog/2020-01-deprecating-antecedents-to-the-conversations-api`):s&&t.warn(`${e} is deprecated. Please check on https://api.slack.com/methods for an alternative.`)}(e,this.logger),function(e,t,i){const s=e=>void 0===e.text||null===e.text||""===e.text,r=()=>`The top-level \`text\` argument is missing in the request payload for a ${e} call - It's a best practice to always provide a \`text\` argument when posting a message. The \`text\` is used in places where the content cannot be rendered such as: system push notifications, assistive technology such as screen readers, etc.`;var n;["chat.postEphemeral","chat.postMessage","chat.scheduleMessage","chat.update"].includes(e)&&"object"==typeof i&&(n=i,Array.isArray(n.attachments)&&n.attachments.length?(e=>Array.isArray(e.attachments)&&e.attachments.some((e=>!e.fallback||""===e.fallback.trim())))(i)&&s(i)&&(t.warn(r()),t.warn(`Additionally, the attachment-level \`fallback\` argument is missing in the request payload for a ${e} call - To avoid this warning, it is recommended to always provide a top-level \`text\` argument when posting a message. Alternatively, you can provide an attachment-level \`fallback\` argument, though this is now considered a legacy field (see https://api.slack.com/reference/messaging/attachments#legacy_fields for more details).`)):s(i)&&t.warn(r()))}(e,this.logger,t),function(e,t,i){["chat.postEphemeral","chat.postMessage","chat.scheduleMessage","files.upload"].includes(e)&&void 0!==(null==i?void 0:i.thread_ts)&&"string"!=typeof(null==i?void 0:i.thread_ts)&&t.warn(R(e))}(e,this.logger,t),"string"==typeof t||"number"==typeof t||"boolean"==typeof t)throw new TypeError("Expected an options argument but instead received a "+typeof t);if((0,Q.warnIfNotUsingFilesUploadV2)(e,this.logger),"files.uploadV2"===e)return this.filesUploadV2(t);const i={};t.token&&(i.Authorization=`Bearer ${t.token}`);const s=await this.makeRequest(e,Object.assign({team_id:this.teamId},t),i),r=await this.buildResult(s);if(this.logger.debug(`http request result: ${JSON.stringify(r)}`),void 0!==r.response_metadata&&void 0!==r.response_metadata.warnings&&r.response_metadata.warnings.forEach(this.logger.warn.bind(this.logger)),void 0!==r.response_metadata&&void 0!==r.response_metadata.messages&&r.response_metadata.messages.forEach((e=>{const t=/\[ERROR\](.*)/,i=/\[WARN\](.*)/;if(t.test(e)){const i=e.match(t);null!=i&&this.logger.error(i[1].trim())}else if(i.test(e)){const t=e.match(i);null!=t&&this.logger.warn(t[1].trim())}})),!r.ok&&"application/gzip"!==s.headers["content-type"])throw(0,I.platformErrorFromResult)(r);if("ok"in r&&!1===r.ok)throw(0,I.platformErrorFromResult)(r);return this.logger.debug(`apiCall('${e}') end`),r}paginate(e,t,i,s){y.cursorPaginationEnabledMethods.has(e)||this.logger.warn(`paginate() called with method ${e}, which is not known to be cursor pagination enabled.`);const r=(()=>{if(void 0!==t&&"number"==typeof t.limit){const{limit:e}=t;return delete t.limit,e}return 200})();function n(){return a(this,arguments,(function*(){let i,s={limit:r};for(void 0!==t&&void 0!==t.cursor&&(s.cursor=t.cursor);void 0===i||void 0!==s;)i=yield o(this.apiCall(e,Object.assign(void 0!==t?t:{},s))),yield yield o(i),s=S(i,r)}))}if(void 0===i)return n.call(this);const l=void 0!==s?s:x;let p=0;return(async()=>{var e,t,s,r;const o=n.call(this),a=(await o.next(void 0)).value;let A=l(void 0,a,p);if(p+=1,i(a))return A;try{for(var u,d=!0,h=c(o);!(e=(u=await h.next()).done);){r=u.value,d=!1;try{const e=r;if(A=l(A,e,p),i(e))return A;p+=1}finally{d=!0}}}catch(e){t={error:e}}finally{try{d||e||!(s=h.return)||await s.call(h)}finally{if(t)throw t.error}}return A})()}async filesUploadV2(e){this.logger.debug("files.uploadV2() start");const t=await this.getAllFileUploads(e);return(await this.fetchAllUploadURLExternal(t)).forEach(((e,i)=>{t[i].upload_url=e.upload_url,t[i].file_id=e.file_id})),await this.postFileUploadsToExternalURL(t,e),{ok:!0,files:await this.completeFileUploads(t)}}async fetchAllUploadURLExternal(e){return Promise.all(e.map((e=>{const t={filename:e.filename,length:e.length,alt_text:e.alt_text,snippet_type:e.snippet_type};return this.files.getUploadURLExternal(t)})))}async completeFileUploads(e){const t=Object.values((0,Q.getAllFileUploadsToComplete)(e));return Promise.all(t.map((e=>this.files.completeUploadExternal(e))))}async postFileUploadsToExternalURL(e,t){return Promise.all(e.map((async e=>{const{upload_url:i,file_id:s,filename:r,data:n}=e,o=n;if(i){const e={};t.token&&(e.Authorization=`Bearer ${t.token}`);const n=await this.makeRequest(i,{body:o},e);if(200!==n.status)return Promise.reject(Error(`Failed to upload file (id:${s}, filename: ${r})`));const a={ok:!0,body:n.data};return Promise.resolve(a)}return Promise.reject(Error(`No upload url found for file (id: ${s}, filename: ${r}`))})))}async getAllFileUploads(e){let t=[];return(e.file||e.content)&&t.push(await(0,Q.getFileUploadJob)(e,this.logger)),e.file_uploads&&(t=t.concat(await(0,Q.getMultipleFileUploadJobs)(e,this.logger))),t}async makeRequest(e,t,i={}){return(0,g.default)((()=>this.requestQueue.add((async()=>{const s=e.startsWith("https")?e:`${this.axios.getUri()+e}`;this.logger.debug(`http request url: ${s}`),this.logger.debug(`http request body: ${JSON.stringify(T(t))}`),this.logger.debug(`http request headers: ${JSON.stringify(T(i))}`);try{const s=Object.assign({headers:i},this.tlsConfig);e.endsWith("admin.analytics.getFile")&&(s.responseType="arraybuffer");const r=await this.axios.post(e,t,s);if(this.logger.debug("http response received"),429===r.status){const i=_(r);if(void 0!==i){if(this.emit(k.RATE_LIMITED,i,{url:e,body:t}),this.rejectRateLimitedCalls)throw new g.AbortError((0,I.rateLimitedErrorWithDelay)(i));throw this.logger.info(`API Call failed due to rate limiting. Will retry in ${i} seconds.`),this.requestQueue.pause(),await(0,b.default)(1e3*i),this.requestQueue.start(),Error(`A rate limit was exceeded (url: ${e}, retry-after: ${i})`)}throw new g.AbortError(new Error(`Retry header did not contain a valid timeout (url: ${e}, retry-after header: ${r.headers["retry-after"]})`))}if(200!==r.status)throw(0,I.httpErrorFromResponse)(r);return r}catch(e){const t=e;if(this.logger.warn("http request failed",t.message),t.request)throw(0,I.requestErrorWithOriginal)(t);throw e}}))),this.retryConfig)}serializeApiCallOptions(e,t){let i=!1;const s=Object.entries(e).map((([e,t])=>{if(null==t)return[];let s=t;return Buffer.isBuffer(t)||(0,h.default)(t)?i=!0:"string"!=typeof t&&"number"!=typeof t&&"boolean"!=typeof t&&(s=JSON.stringify(t)),[e,s]}));if(i){this.logger.debug("Request arguments contain binary data");const e=s.reduce(((e,[t,i])=>{if(Buffer.isBuffer(i)||(0,h.default)(i)){const s={};s.filename=(()=>{const e=i;return"string"==typeof e.name?(0,A.basename)(e.name):"string"==typeof e.path?(0,A.basename)(e.path):"Untitled"})(),e.append(t,i,s)}else void 0!==t&&void 0!==i&&e.append(t,i);return e}),new E.default);return Object.entries(e.getHeaders()).forEach((([e,i])=>{t[e]=i})),e}return t["Content-Type"]="application/x-www-form-urlencoded",(0,p.stringify)(s.reduce(((e,[t,i])=>(void 0!==t&&void 0!==i&&(e[t]=i),e)),{}))}async buildResult(e){let{data:t}=e;const i="application/gzip"===e.headers["content-type"];if(i)try{const e=await new Promise(((e,i)=>{u.default.unzip(t,((t,s)=>t?i(t):e(s.toString().split("\n"))))})).then((e=>e)).catch((e=>{throw e})),i=[];Array.isArray(e)&&e.forEach((e=>{e&&e.length>0&&i.push(JSON.parse(e))})),t={file_data:i}}catch(e){t={ok:!1,error:e}}else i||"/api/admin.analytics.getFile"!==e.request.path||(t=JSON.parse((new d.TextDecoder).decode(t)));if("string"==typeof t)try{t=JSON.parse(t)}catch(e){t={ok:!1,error:t}}void 0===t.response_metadata&&(t.response_metadata={}),void 0!==e.headers["x-oauth-scopes"]&&(t.response_metadata.scopes=e.headers["x-oauth-scopes"].trim().split(/\s*,\s*/)),void 0!==e.headers["x-accepted-oauth-scopes"]&&(t.response_metadata.acceptedScopes=e.headers["x-accepted-oauth-scopes"].trim().split(/\s*,\s*/));const s=_(e);return void 0!==s&&(t.response_metadata.retryAfter=s),t}}function S(e,t){if(void 0!==e&&void 0!==e.response_metadata&&void 0!==e.response_metadata.next_cursor&&""!==e.response_metadata.next_cursor)return{limit:t,cursor:e.response_metadata.next_cursor}}function _(e){if(void 0!==e.headers["retry-after"]){const t=parseInt(e.headers["retry-after"],10);if(!Number.isNaN(t))return t}}function R(e){return`The given thread_ts value in the request payload for a ${e} call is a float value. We highly recommend using a string value instead.`}function T(e){return Object.entries(e).map((([e,t])=>{if(null==t)return[];let i=t;return(null!==e.match(/.*token.*/)||e.match(/[Aa]uthorization/))&&(i="[[REDACTED]]"),Buffer.isBuffer(t)||(0,h.default)(t)?i="[[BINARY VALUE OMITTED]]":"string"!=typeof t&&"number"!=typeof t&&"boolean"!=typeof t&&(i=JSON.stringify(t)),[e,i]})).reduce(((e,[t,i])=>(void 0!==t&&void 0!==i&&(e[t]=i),e)),{})}t.WebClient=D,D.loggerName="WebClient",t.default=D,t.buildThreadTsWarningMessage=R},47056:(e,t)=>{"use strict";var i;function s(e,t){const i=e;return i.code=t,i}Object.defineProperty(t,"__esModule",{value:!0}),t.rateLimitedErrorWithDelay=t.platformErrorFromResult=t.httpErrorFromResponse=t.requestErrorWithOriginal=t.errorWithCode=t.ErrorCode=void 0,function(e){e.RequestError="slack_webapi_request_error",e.HTTPError="slack_webapi_http_error",e.PlatformError="slack_webapi_platform_error",e.RateLimitedError="slack_webapi_rate_limited_error",e.FileUploadInvalidArgumentsError="slack_webapi_file_upload_invalid_args_error",e.FileUploadReadFileDataError="slack_webapi_file_upload_read_file_data_error"}(i=t.ErrorCode||(t.ErrorCode={})),t.errorWithCode=s,t.requestErrorWithOriginal=function(e){const t=s(new Error(`A request error occurred: ${e.message}`),i.RequestError);return t.original=e,t},t.httpErrorFromResponse=function(e){const t=s(new Error(`An HTTP protocol error occurred: statusCode = ${e.status}`),i.HTTPError);t.statusCode=e.status,t.statusMessage=e.statusText;const r={};return Object.keys(e.headers).forEach((t=>{t&&e.headers[t]&&(r[t]=e.headers[t])})),t.headers=r,t.body=e.data,t},t.platformErrorFromResult=function(e){const t=s(new Error(`An API error occurred: ${e.error}`),i.PlatformError);return t.data=e,t},t.rateLimitedErrorWithDelay=function(e){const t=s(new Error(`A rate-limit has been reached, you may retry this request in ${e} seconds`),i.RateLimitedError);return t.retryAfter=e,t}},28666:(e,t,i)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.buildInvalidFilesUploadParamError=t.buildMultipleChannelsErrorMsg=t.buildChannelsWarning=t.buildFilesUploadMissingMessage=t.buildGeneralFilesUploadWarning=t.buildLegacyMethodWarning=t.buildMissingExtensionWarning=t.buildMissingFileNameWarning=t.buildLegacyFileTypeWarning=t.buildFileSizeErrorMsg=t.buildMissingFileIdError=t.warnIfLegacyFileType=t.warnIfMissingOrInvalidFileNameAndDefault=t.errorIfInvalidOrMissingFileData=t.errorIfChannelsCsv=t.warnIfChannels=t.warnIfNotUsingFilesUploadV2=t.getAllFileUploadsToComplete=t.getFileDataAsStream=t.getFileDataLength=t.getFileData=t.getMultipleFileUploadJobs=t.getFileUploadJob=void 0;const s=i(57147),r=i(12781),n=i(47056);async function o(e,t){var i,s,r,n;h(e,t),p(e,t),A(e);const o=d(e,t),l=await a(e),u=c(l);return{alt_text:e.alt_text,channel_id:null!==(i=e.channels)&&void 0!==i?i:e.channel_id,content:e.content,file:e.file,filename:null!==(s=e.filename)&&void 0!==s?s:o,initial_comment:e.initial_comment,snippet_type:e.snippet_type,thread_ts:e.thread_ts,title:null!==(r=e.title)&&void 0!==r?r:null!==(n=e.filename)&&void 0!==n?n:o,data:l,length:u}}async function a(e){u(e);const{file:t,content:i}=e;if(t){if(Buffer.isBuffer(t))return t;if("string"==typeof t)try{return(0,s.readFileSync)(t)}catch(e){throw(0,n.errorWithCode)(new Error(`Unable to resolve file data for ${t}. Please supply a filepath string, or binary data Buffer or String directly.`),n.ErrorCode.FileUploadInvalidArgumentsError)}const e=await l(t);if(e)return e}if(i)return Buffer.from(i);throw(0,n.errorWithCode)(new Error("There was an issue getting the file data for the file or content supplied"),n.ErrorCode.FileUploadReadFileDataError)}function c(e){if(e)return Buffer.byteLength(e,"utf8");throw(0,n.errorWithCode)(new Error("There was an issue calculating the size of your file"),n.ErrorCode.FileUploadReadFileDataError)}async function l(e){const t=[];return new Promise(((i,s)=>{e.on("readable",(()=>{let i;for(;null!==(i=e.read());)t.push(i)})),e.on("end",(()=>{if(t.length>0){const e=Buffer.concat(t);i(e)}else s(Error("No data in supplied file"))}))}))}function p(e,t){e.channels&&t.warn("Although the 'channels' parameter is still supported for smoother migration from legacy files.upload, we recommend using the new channel_id parameter with a single str value instead (e.g. 'C12345').")}function A(e){if((e.channels?e.channels.split(","):[]).length>1)throw(0,n.errorWithCode)(new Error("Sharing files with multiple channels is no longer supported in v2. Share files in each channel separately instead."),n.ErrorCode.FileUploadInvalidArgumentsError)}function u(e){const{file:t,content:i}=e;if(!t&&!i||t&&i)throw(0,n.errorWithCode)(new Error("Either a file or content field is required for valid file upload. You cannot supply both"),n.ErrorCode.FileUploadInvalidArgumentsError);if(t&&!("string"==typeof t||Buffer.isBuffer(t)||t instanceof r.Readable))throw(0,n.errorWithCode)(new Error("file must be a valid string path, buffer or Readable"),n.ErrorCode.FileUploadInvalidArgumentsError);if(i&&"string"!=typeof i)throw(0,n.errorWithCode)(new Error("content must be a string"),n.ErrorCode.FileUploadInvalidArgumentsError)}function d(e,t){var i;const s=`file.${null!==(i=e.filetype)&&void 0!==i?i:"txt"}`,{filename:r}=e;return r?(r.split(".").length<2&&t.warn(m(r)),r):(t.warn("filename is a required field for files.uploadV2. \n For backwards compatibility and ease of migration, defaulting the filename. For best experience and consistent unfurl behavior, you should set the filename property with correct file extension, e.g. image.png, text.txt"),s)}function h(e,t){e.filetype&&t.warn("filetype is no longer a supported field in files.uploadV2. \nPlease remove this field. To indicate file type, please do so via the required filename property using the appropriate file extension, e.g. image.png, text.txt")}function m(e){return`filename supplied '${e}' may be missing a proper extension. Missing extenions may result in unexpected unfurl behavior when shared`}function g(e){return`${e} may cause some issues like timeouts for relatively large files.`}t.getFileUploadJob=o,t.getMultipleFileUploadJobs=async function(e,t){if(e.file_uploads)return Promise.all(e.file_uploads.map((i=>{const{channel_id:s,channels:r,initial_comment:a,thread_ts:c}=i;if(s||r||a||c)throw(0,n.errorWithCode)(new Error("You may supply file_uploads only for a single channel, comment, thread respectively. Therefore, please supply any channel_id, initial_comment, thread_ts in the top-layer."),n.ErrorCode.FileUploadInvalidArgumentsError);return o(Object.assign(Object.assign({},i),{channels:e.channels,channel_id:e.channel_id,initial_comment:e.initial_comment,thread_ts:e.thread_ts}),t)})));throw new Error("Something went wrong with processing file_uploads")},t.getFileData=a,t.getFileDataLength=c,t.getFileDataAsStream=l,t.getAllFileUploadsToComplete=function(e){const t={};return e.forEach((e=>{const{channel_id:i,thread_ts:s,initial_comment:r,file_id:n,title:o}=e;if(!n)throw new Error("Missing required file id for file upload completion");{const e=`:::${i}:::${s}:::${r}`;Object.prototype.hasOwnProperty.call(t,e)?t[e].files.push({id:n,title:o}):t[e]={files:[{id:n,title:o}],channel_id:i,initial_comment:r,thread_ts:s}}})),t},t.warnIfNotUsingFilesUploadV2=function(e,t){const i=["files.upload"].includes(e);"files.upload"===e&&t.warn(g(e)),i&&t.info("Our latest recommendation is to use client.files.uploadV2() method, which is mostly compatible and much stabler, instead.")},t.warnIfChannels=p,t.errorIfChannelsCsv=A,t.errorIfInvalidOrMissingFileData=u,t.warnIfMissingOrInvalidFileNameAndDefault=d,t.warnIfLegacyFileType=h,t.buildMissingFileIdError=function(){return"Missing required file id for file upload completion"},t.buildFileSizeErrorMsg=function(){return"There was an issue calculating the size of your file"},t.buildLegacyFileTypeWarning=function(){return"filetype is no longer a supported field in files.uploadV2. \nPlease remove this field. To indicate file type, please do so via the required filename property using the appropriate file extension, e.g. image.png, text.txt"},t.buildMissingFileNameWarning=function(){return"filename is a required field for files.uploadV2. \n For backwards compatibility and ease of migration, defaulting the filename. For best experience and consistent unfurl behavior, you should set the filename property with correct file extension, e.g. image.png, text.txt"},t.buildMissingExtensionWarning=m,t.buildLegacyMethodWarning=g,t.buildGeneralFilesUploadWarning=function(){return"Our latest recommendation is to use client.files.uploadV2() method, which is mostly compatible and much stabler, instead."},t.buildFilesUploadMissingMessage=function(){return"Something went wrong with processing file_uploads"},t.buildChannelsWarning=function(){return"Although the 'channels' parameter is still supported for smoother migration from legacy files.upload, we recommend using the new channel_id parameter with a single str value instead (e.g. 'C12345')."},t.buildMultipleChannelsErrorMsg=function(){return"Sharing files with multiple channels is no longer supported in v2. Share files in each channel separately instead."},t.buildInvalidFilesUploadParamError=function(){return"You may supply file_uploads only for a single channel, comment, thread respectively. Therefore, please supply any channel_id, initial_comment, thread_ts in the top-layer."}},83313:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return new Promise((t=>{setTimeout(t,e)}))}},85314:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i);var r=Object.getOwnPropertyDescriptor(t,i);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[i]}}),Object.defineProperty(e,s,r)}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__exportStar||function(e,t){for(var i in e)"default"===i||Object.prototype.hasOwnProperty.call(t,i)||s(t,e,i)},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.addAppMetadata=t.retryPolicies=t.ErrorCode=t.LogLevel=t.WebClientEvent=t.WebClient=void 0;var o=i(11055);Object.defineProperty(t,"WebClient",{enumerable:!0,get:function(){return o.WebClient}}),Object.defineProperty(t,"WebClientEvent",{enumerable:!0,get:function(){return o.WebClientEvent}});var a=i(94139);Object.defineProperty(t,"LogLevel",{enumerable:!0,get:function(){return a.LogLevel}});var c=i(47056);Object.defineProperty(t,"ErrorCode",{enumerable:!0,get:function(){return c.ErrorCode}});var l=i(39847);Object.defineProperty(t,"retryPolicies",{enumerable:!0,get:function(){return n(l).default}});var p=i(57390);Object.defineProperty(t,"addAppMetadata",{enumerable:!0,get:function(){return p.addAppMetadata}}),r(i(25242),t),r(i(82356),t)},57390:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i);var r=Object.getOwnPropertyDescriptor(t,i);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[i]}}),Object.defineProperty(e,s,r)}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.prototype.hasOwnProperty.call(e,i)&&s(t,e,i);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.getUserAgent=t.addAppMetadata=void 0;const o=n(i(22037)),a=i(71017),c=i(10191);function l(e){return e.replace("/",":")}const p=`${l(c.name)}/${c.version} ${(0,a.basename)(process.title)}/${process.version.replace("v","")} ${o.platform()}/${o.release()}`,A={};t.addAppMetadata=function({name:e,version:t}){A[l(e)]=t},t.getUserAgent=function(){const e=Object.entries(A).map((([e,t])=>`${e}/${t}`)).join(" ");return(e.length>0?`${e} `:"")+p}},94139:(e,t,i)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getLogger=t.LogLevel=void 0;const s=i(94832);var r=i(94832);Object.defineProperty(t,"LogLevel",{enumerable:!0,get:function(){return r.LogLevel}});let n=0;t.getLogger=function(e,t,i){const r=n;n+=1;const o=void 0!==i?i:new s.ConsoleLogger;return o.setName(`web-api:${e}:${r}`),void 0!==t&&o.setLevel(t),o}},25242:function(e,t,i){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i);var r=Object.getOwnPropertyDescriptor(t,i);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[i]}}),Object.defineProperty(e,s,r)}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),r=this&&this.__exportStar||function(e,t){for(var i in e)"default"===i||Object.prototype.hasOwnProperty.call(t,i)||s(t,e,i)};Object.defineProperty(t,"__esModule",{value:!0}),t.cursorPaginationEnabledMethods=t.Methods=void 0;const n=i(91906),o=i(11055);function a(e,t){return e.apiCall.bind(e,t)}function c(e){return e.filesUploadV2.bind(e)}class l extends n.EventEmitter{constructor(){if(super(),this.admin={analytics:{getFile:a(this,"admin.analytics.getFile")},apps:{approve:a(this,"admin.apps.approve"),approved:{list:a(this,"admin.apps.approved.list")},clearResolution:a(this,"admin.apps.clearResolution"),requests:{cancel:a(this,"admin.apps.requests.cancel"),list:a(this,"admin.apps.requests.list")},restrict:a(this,"admin.apps.restrict"),restricted:{list:a(this,"admin.apps.restricted.list")},uninstall:a(this,"admin.apps.uninstall"),activities:{list:a(this,"admin.apps.activities.list")}},auth:{policy:{assignEntities:a(this,"admin.auth.policy.assignEntities"),getEntities:a(this,"admin.auth.policy.getEntities"),removeEntities:a(this,"admin.auth.policy.removeEntities")}},barriers:{create:a(this,"admin.barriers.create"),delete:a(this,"admin.barriers.delete"),list:a(this,"admin.barriers.list"),update:a(this,"admin.barriers.update")},conversations:{archive:a(this,"admin.conversations.archive"),bulkArchive:a(this,"admin.conversations.bulkArchive"),bulkDelete:a(this,"admin.conversations.bulkDelete"),bulkMove:a(this,"admin.conversations.bulkMove"),convertToPrivate:a(this,"admin.conversations.convertToPrivate"),convertToPublic:a(this,"admin.conversations.convertToPublic"),create:a(this,"admin.conversations.create"),delete:a(this,"admin.conversations.delete"),disconnectShared:a(this,"admin.conversations.disconnectShared"),ekm:{listOriginalConnectedChannelInfo:a(this,"admin.conversations.ekm.listOriginalConnectedChannelInfo")},getConversationPrefs:a(this,"admin.conversations.getConversationPrefs"),getTeams:a(this,"admin.conversations.getTeams"),invite:a(this,"admin.conversations.invite"),rename:a(this,"admin.conversations.rename"),restrictAccess:{addGroup:a(this,"admin.conversations.restrictAccess.addGroup"),listGroups:a(this,"admin.conversations.restrictAccess.listGroups"),removeGroup:a(this,"admin.conversations.restrictAccess.removeGroup")},getCustomRetention:a(this,"admin.conversations.getCustomRetention"),setCustomRetention:a(this,"admin.conversations.setCustomRetention"),removeCustomRetention:a(this,"admin.conversations.removeCustomRetention"),lookup:a(this,"admin.conversations.lookup"),search:a(this,"admin.conversations.search"),setConversationPrefs:a(this,"admin.conversations.setConversationPrefs"),setTeams:a(this,"admin.conversations.setTeams"),unarchive:a(this,"admin.conversations.unarchive")},emoji:{add:a(this,"admin.emoji.add"),addAlias:a(this,"admin.emoji.addAlias"),list:a(this,"admin.emoji.list"),remove:a(this,"admin.emoji.remove"),rename:a(this,"admin.emoji.rename")},functions:{list:a(this,"admin.functions.list"),permissions:{lookup:a(this,"admin.functions.permissions.lookup"),set:a(this,"admin.functions.permissions.set")}},inviteRequests:{approve:a(this,"admin.inviteRequests.approve"),approved:{list:a(this,"admin.inviteRequests.approved.list")},denied:{list:a(this,"admin.inviteRequests.denied.list")},deny:a(this,"admin.inviteRequests.deny"),list:a(this,"admin.inviteRequests.list")},teams:{admins:{list:a(this,"admin.teams.admins.list")},create:a(this,"admin.teams.create"),list:a(this,"admin.teams.list"),owners:{list:a(this,"admin.teams.owners.list")},settings:{info:a(this,"admin.teams.settings.info"),setDefaultChannels:a(this,"admin.teams.settings.setDefaultChannels"),setDescription:a(this,"admin.teams.settings.setDescription"),setDiscoverability:a(this,"admin.teams.settings.setDiscoverability"),setIcon:a(this,"admin.teams.settings.setIcon"),setName:a(this,"admin.teams.settings.setName")}},roles:{addAssignments:a(this,"admin.roles.addAssignments"),listAssignments:a(this,"admin.roles.listAssignments"),removeAssignments:a(this,"admin.roles.removeAssignments")},usergroups:{addChannels:a(this,"admin.usergroups.addChannels"),addTeams:a(this,"admin.usergroups.addTeams"),listChannels:a(this,"admin.usergroups.listChannels"),removeChannels:a(this,"admin.usergroups.removeChannels")},users:{assign:a(this,"admin.users.assign"),invite:a(this,"admin.users.invite"),list:a(this,"admin.users.list"),remove:a(this,"admin.users.remove"),session:{list:a(this,"admin.users.session.list"),reset:a(this,"admin.users.session.reset"),resetBulk:a(this,"admin.users.session.resetBulk"),invalidate:a(this,"admin.users.session.invalidate"),getSettings:a(this,"admin.users.session.getSettings"),setSettings:a(this,"admin.users.session.setSettings"),clearSettings:a(this,"admin.users.session.clearSettings")},unsupportedVersions:{export:a(this,"admin.users.unsupportedVersions.export")},setAdmin:a(this,"admin.users.setAdmin"),setExpiration:a(this,"admin.users.setExpiration"),setOwner:a(this,"admin.users.setOwner"),setRegular:a(this,"admin.users.setRegular")},workflows:{search:a(this,"admin.workflows.search"),unpublish:a(this,"admin.workflows.unpublish"),collaborators:{add:a(this,"admin.workflows.collaborators.add"),remove:a(this,"admin.workflows.collaborators.remove")},permissions:{lookup:a(this,"admin.workflows.permissions.lookup")}}},this.api={test:a(this,"api.test")},this.apps={connections:{open:a(this,"apps.connections.open")},event:{authorizations:{list:a(this,"apps.event.authorizations.list")}},manifest:{create:a(this,"apps.manifest.create"),delete:a(this,"apps.manifest.delete"),export:a(this,"apps.manifest.export"),update:a(this,"apps.manifest.update"),validate:a(this,"apps.manifest.validate")},uninstall:a(this,"apps.uninstall")},this.auth={revoke:a(this,"auth.revoke"),teams:{list:a(this,"auth.teams.list")},test:a(this,"auth.test")},this.bots={info:a(this,"bots.info")},this.bookmarks={add:a(this,"bookmarks.add"),edit:a(this,"bookmarks.edit"),list:a(this,"bookmarks.list"),remove:a(this,"bookmarks.remove")},this.calls={add:a(this,"calls.add"),end:a(this,"calls.end"),info:a(this,"calls.info"),update:a(this,"calls.update"),participants:{add:a(this,"calls.participants.add"),remove:a(this,"calls.participants.remove")}},this.chat={delete:a(this,"chat.delete"),deleteScheduledMessage:a(this,"chat.deleteScheduledMessage"),getPermalink:a(this,"chat.getPermalink"),meMessage:a(this,"chat.meMessage"),postEphemeral:a(this,"chat.postEphemeral"),postMessage:a(this,"chat.postMessage"),scheduleMessage:a(this,"chat.scheduleMessage"),scheduledMessages:{list:a(this,"chat.scheduledMessages.list")},unfurl:a(this,"chat.unfurl"),update:a(this,"chat.update")},this.conversations={acceptSharedInvite:a(this,"conversations.acceptSharedInvite"),approveSharedInvite:a(this,"conversations.approveSharedInvite"),archive:a(this,"conversations.archive"),close:a(this,"conversations.close"),create:a(this,"conversations.create"),declineSharedInvite:a(this,"conversations.declineSharedInvite"),history:a(this,"conversations.history"),info:a(this,"conversations.info"),invite:a(this,"conversations.invite"),inviteShared:a(this,"conversations.inviteShared"),join:a(this,"conversations.join"),kick:a(this,"conversations.kick"),leave:a(this,"conversations.leave"),list:a(this,"conversations.list"),listConnectInvites:a(this,"conversations.listConnectInvites"),mark:a(this,"conversations.mark"),members:a(this,"conversations.members"),open:a(this,"conversations.open"),rename:a(this,"conversations.rename"),replies:a(this,"conversations.replies"),setPurpose:a(this,"conversations.setPurpose"),setTopic:a(this,"conversations.setTopic"),unarchive:a(this,"conversations.unarchive")},this.dialog={open:a(this,"dialog.open")},this.dnd={endDnd:a(this,"dnd.endDnd"),endSnooze:a(this,"dnd.endSnooze"),info:a(this,"dnd.info"),setSnooze:a(this,"dnd.setSnooze"),teamInfo:a(this,"dnd.teamInfo")},this.emoji={list:a(this,"emoji.list")},this.files={delete:a(this,"files.delete"),info:a(this,"files.info"),list:a(this,"files.list"),revokePublicURL:a(this,"files.revokePublicURL"),sharedPublicURL:a(this,"files.sharedPublicURL"),upload:a(this,"files.upload"),uploadV2:c(this),getUploadURLExternal:a(this,"files.getUploadURLExternal"),completeUploadExternal:a(this,"files.completeUploadExternal"),comments:{delete:a(this,"files.comments.delete")},remote:{info:a(this,"files.remote.info"),list:a(this,"files.remote.list"),add:a(this,"files.remote.add"),update:a(this,"files.remote.update"),remove:a(this,"files.remote.remove"),share:a(this,"files.remote.share")}},this.migration={exchange:a(this,"migration.exchange")},this.oauth={access:a(this,"oauth.access"),v2:{access:a(this,"oauth.v2.access"),exchange:a(this,"oauth.v2.exchange")}},this.openid={connect:{token:a(this,"openid.connect.token"),userInfo:a(this,"openid.connect.userInfo")}},this.pins={add:a(this,"pins.add"),list:a(this,"pins.list"),remove:a(this,"pins.remove")},this.reactions={add:a(this,"reactions.add"),get:a(this,"reactions.get"),list:a(this,"reactions.list"),remove:a(this,"reactions.remove")},this.reminders={add:a(this,"reminders.add"),complete:a(this,"reminders.complete"),delete:a(this,"reminders.delete"),info:a(this,"reminders.info"),list:a(this,"reminders.list")},this.rtm={connect:a(this,"rtm.connect"),start:a(this,"rtm.start")},this.search={all:a(this,"search.all"),files:a(this,"search.files"),messages:a(this,"search.messages")},this.stars={add:a(this,"stars.add"),list:a(this,"stars.list"),remove:a(this,"stars.remove")},this.team={accessLogs:a(this,"team.accessLogs"),billableInfo:a(this,"team.billableInfo"),billing:{info:a(this,"team.billing.info")},info:a(this,"team.info"),integrationLogs:a(this,"team.integrationLogs"),preferences:{list:a(this,"team.preferences.list")},profile:{get:a(this,"team.profile.get")}},this.tooling={tokens:{rotate:a(this,"tooling.tokens.rotate")}},this.usergroups={create:a(this,"usergroups.create"),disable:a(this,"usergroups.disable"),enable:a(this,"usergroups.enable"),list:a(this,"usergroups.list"),update:a(this,"usergroups.update"),users:{list:a(this,"usergroups.users.list"),update:a(this,"usergroups.users.update")}},this.users={conversations:a(this,"users.conversations"),deletePhoto:a(this,"users.deletePhoto"),getPresence:a(this,"users.getPresence"),identity:a(this,"users.identity"),info:a(this,"users.info"),list:a(this,"users.list"),lookupByEmail:a(this,"users.lookupByEmail"),setPhoto:a(this,"users.setPhoto"),setPresence:a(this,"users.setPresence"),profile:{get:a(this,"users.profile.get"),set:a(this,"users.profile.set")}},this.views={open:a(this,"views.open"),publish:a(this,"views.publish"),push:a(this,"views.push"),update:a(this,"views.update")},this.workflows={stepCompleted:a(this,"workflows.stepCompleted"),stepFailed:a(this,"workflows.stepFailed"),updateStep:a(this,"workflows.updateStep")},this.channels={archive:a(this,"channels.archive"),create:a(this,"channels.create"),history:a(this,"channels.history"),info:a(this,"channels.info"),invite:a(this,"channels.invite"),join:a(this,"channels.join"),kick:a(this,"channels.kick"),leave:a(this,"channels.leave"),list:a(this,"channels.list"),mark:a(this,"channels.mark"),rename:a(this,"channels.rename"),replies:a(this,"channels.replies"),setPurpose:a(this,"channels.setPurpose"),setTopic:a(this,"channels.setTopic"),unarchive:a(this,"channels.unarchive")},this.groups={archive:a(this,"groups.archive"),create:a(this,"groups.create"),createChild:a(this,"groups.createChild"),history:a(this,"groups.history"),info:a(this,"groups.info"),invite:a(this,"groups.invite"),kick:a(this,"groups.kick"),leave:a(this,"groups.leave"),list:a(this,"groups.list"),mark:a(this,"groups.mark"),open:a(this,"groups.open"),rename:a(this,"groups.rename"),replies:a(this,"groups.replies"),setPurpose:a(this,"groups.setPurpose"),setTopic:a(this,"groups.setTopic"),unarchive:a(this,"groups.unarchive")},this.im={close:a(this,"im.close"),history:a(this,"im.history"),list:a(this,"im.list"),mark:a(this,"im.mark"),open:a(this,"im.open"),replies:a(this,"im.replies")},this.mpim={close:a(this,"mpim.close"),history:a(this,"mpim.history"),list:a(this,"mpim.list"),mark:a(this,"mpim.mark"),open:a(this,"mpim.open"),replies:a(this,"mpim.replies")},new.target!==o.WebClient&&!(new.target.prototype instanceof o.WebClient))throw new Error("Attempt to inherit from WebClient methods without inheriting from WebClient")}}t.Methods=l,t.cursorPaginationEnabledMethods=new Set,t.cursorPaginationEnabledMethods.add("admin.apps.approved.list"),t.cursorPaginationEnabledMethods.add("admin.apps.requests.list"),t.cursorPaginationEnabledMethods.add("admin.apps.restricted.list"),t.cursorPaginationEnabledMethods.add("admin.apps.activities.list"),t.cursorPaginationEnabledMethods.add("admin.auth.policy.getEntities"),t.cursorPaginationEnabledMethods.add("admin.barriers.list"),t.cursorPaginationEnabledMethods.add("admin.conversations.lookup"),t.cursorPaginationEnabledMethods.add("admin.conversations.ekm.listOriginalConnectedChannelInfo"),t.cursorPaginationEnabledMethods.add("admin.conversations.getTeams"),t.cursorPaginationEnabledMethods.add("admin.conversations.search"),t.cursorPaginationEnabledMethods.add("admin.emoji.list"),t.cursorPaginationEnabledMethods.add("admin.inviteRequests.approved.list"),t.cursorPaginationEnabledMethods.add("admin.inviteRequests.denied.list"),t.cursorPaginationEnabledMethods.add("admin.inviteRequests.list"),t.cursorPaginationEnabledMethods.add("admin.roles.listAssignments"),t.cursorPaginationEnabledMethods.add("admin.inviteRequests.list"),t.cursorPaginationEnabledMethods.add("admin.teams.admins.list"),t.cursorPaginationEnabledMethods.add("admin.teams.list"),t.cursorPaginationEnabledMethods.add("admin.teams.owners.list"),t.cursorPaginationEnabledMethods.add("admin.users.list"),t.cursorPaginationEnabledMethods.add("admin.users.session.list"),t.cursorPaginationEnabledMethods.add("admin.worfklows.search"),t.cursorPaginationEnabledMethods.add("apps.event.authorizations.list"),t.cursorPaginationEnabledMethods.add("auth.teams.list"),t.cursorPaginationEnabledMethods.add("channels.list"),t.cursorPaginationEnabledMethods.add("chat.scheduledMessages.list"),t.cursorPaginationEnabledMethods.add("conversations.history"),t.cursorPaginationEnabledMethods.add("conversations.list"),t.cursorPaginationEnabledMethods.add("conversations.listConnectInvites"),t.cursorPaginationEnabledMethods.add("conversations.members"),t.cursorPaginationEnabledMethods.add("conversations.replies"),t.cursorPaginationEnabledMethods.add("files.info"),t.cursorPaginationEnabledMethods.add("files.remote.list"),t.cursorPaginationEnabledMethods.add("groups.list"),t.cursorPaginationEnabledMethods.add("im.list"),t.cursorPaginationEnabledMethods.add("mpim.list"),t.cursorPaginationEnabledMethods.add("reactions.list"),t.cursorPaginationEnabledMethods.add("stars.list"),t.cursorPaginationEnabledMethods.add("team.accessLogs"),t.cursorPaginationEnabledMethods.add("users.conversations"),t.cursorPaginationEnabledMethods.add("users.list"),r(i(17578),t)},82356:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0})},39847:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.rapidRetryPolicy=t.fiveRetriesInFiveMinutes=t.tenRetriesInAboutThirtyMinutes=void 0,t.tenRetriesInAboutThirtyMinutes={retries:10,factor:1.96821,randomize:!0},t.fiveRetriesInFiveMinutes={retries:5,factor:3.86},t.rapidRetryPolicy={minTimeout:0,maxTimeout:1};const i={tenRetriesInAboutThirtyMinutes:t.tenRetriesInAboutThirtyMinutes,fiveRetriesInFiveMinutes:t.fiveRetriesInFiveMinutes,rapidRetryPolicy:t.rapidRetryPolicy};t.default=i},14686:(e,t,i)=>{"use strict";const s=i(96066),r=i(53072);class n extends Error{constructor(e){if(!Array.isArray(e))throw new TypeError("Expected input to be an Array, got "+typeof e);let t=(e=[...e].map((e=>e instanceof Error?e:null!==e&&"object"==typeof e?Object.assign(new Error(e.message),e):new Error(e)))).map((e=>"string"==typeof e.stack?r(e.stack).replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g,""):String(e))).join("\n");t="\n"+s(t,4),super(t),this.name="AggregateError",Object.defineProperty(this,"_errors",{value:e})}*[Symbol.iterator](){for(const e of this._errors)yield e}}e.exports=n},86873:e=>{"use strict";e.exports=({onlyFirst:e=!1}={})=>{const t=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(t,e?void 0:"g")}},78413:(e,t,i)=>{"use strict";e=i.nmd(e);const s=(e,t)=>(...i)=>`[${e(...i)+t}m`,r=(e,t)=>(...i)=>{const s=e(...i);return`[${38+t};5;${s}m`},n=(e,t)=>(...i)=>{const s=e(...i);return`[${38+t};2;${s[0]};${s[1]};${s[2]}m`},o=e=>e,a=(e,t,i)=>[e,t,i],c=(e,t,i)=>{Object.defineProperty(e,t,{get:()=>{const s=i();return Object.defineProperty(e,t,{value:s,enumerable:!0,configurable:!0}),s},enumerable:!0,configurable:!0})};let l;const p=(e,t,s,r)=>{void 0===l&&(l=i(60398));const n=r?10:0,o={};for(const[i,r]of Object.entries(l)){const a="ansi16"===i?"ansi":i;i===t?o[a]=e(s,n):"object"==typeof r&&(o[a]=e(r[t],n))}return o};Object.defineProperty(e,"exports",{enumerable:!0,get:function(){const e=new Map,t={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};t.color.gray=t.color.blackBright,t.bgColor.bgGray=t.bgColor.bgBlackBright,t.color.grey=t.color.blackBright,t.bgColor.bgGrey=t.bgColor.bgBlackBright;for(const[i,s]of Object.entries(t)){for(const[i,r]of Object.entries(s))t[i]={open:`[${r[0]}m`,close:`[${r[1]}m`},s[i]=t[i],e.set(r[0],r[1]);Object.defineProperty(t,i,{value:s,enumerable:!1})}return Object.defineProperty(t,"codes",{value:e,enumerable:!1}),t.color.close="",t.bgColor.close="",c(t.color,"ansi",(()=>p(s,"ansi16",o,!1))),c(t.color,"ansi256",(()=>p(r,"ansi256",o,!1))),c(t.color,"ansi16m",(()=>p(n,"rgb",a,!1))),c(t.bgColor,"ansi",(()=>p(s,"ansi16",o,!0))),c(t.bgColor,"ansi256",(()=>p(r,"ansi256",o,!0))),c(t.bgColor,"ansi16m",(()=>p(n,"rgb",a,!0))),t}})},62720:(e,t,i)=>{e.exports={parallel:i(61286),serial:i(74694),serialOrdered:i(87458)}},34653:e=>{function t(e){"function"==typeof this.jobs[e]&&this.jobs[e]()}e.exports=function(e){Object.keys(e.jobs).forEach(t.bind(e)),e.jobs={}}},5209:(e,t,i)=>{var s=i(45623);e.exports=function(e){var t=!1;return s((function(){t=!0})),function(i,r){t?e(i,r):s((function(){e(i,r)}))}}},45623:e=>{e.exports=function(e){var t="function"==typeof setImmediate?setImmediate:"object"==typeof process&&"function"==typeof process.nextTick?process.nextTick:null;t?t(e):setTimeout(e,0)}},28773:(e,t,i)=>{var s=i(5209),r=i(34653);e.exports=function(e,t,i,n){var o=i.keyedList?i.keyedList[i.index]:i.index;i.jobs[o]=function(e,t,i,r){return 2==e.length?e(i,s(r)):e(i,t,s(r))}(t,o,e[o],(function(e,t){o in i.jobs&&(delete i.jobs[o],e?r(i):i.results[o]=t,n(e,i.results))}))}},67630:e=>{e.exports=function(e,t){var i=!Array.isArray(e),s={index:0,keyedList:i||t?Object.keys(e):null,jobs:{},results:i?{}:[],size:i?Object.keys(e).length:e.length};return t&&s.keyedList.sort(i?t:function(i,s){return t(e[i],e[s])}),s}},45067:(e,t,i)=>{var s=i(34653),r=i(5209);e.exports=function(e){Object.keys(this.jobs).length&&(this.index=this.size,s(this),r(e)(null,this.results))}},61286:(e,t,i)=>{var s=i(28773),r=i(67630),n=i(45067);e.exports=function(e,t,i){for(var o=r(e);o.index<(o.keyedList||e).length;)s(e,t,o,(function(e,t){e?i(e,t):0!==Object.keys(o.jobs).length||i(null,o.results)})),o.index++;return n.bind(o,i)}},74694:(e,t,i)=>{var s=i(87458);e.exports=function(e,t,i){return s(e,t,null,i)}},87458:(e,t,i)=>{var s=i(28773),r=i(67630),n=i(45067);function o(e,t){return et?1:0}e.exports=function(e,t,i,o){var a=r(e,i);return s(e,t,a,(function i(r,n){r?o(r,n):(a.index++,a.index<(a.keyedList||e).length?s(e,t,a,i):o(null,a.results))})),n.bind(a,o)},e.exports.ascending=o,e.exports.descending=function(e,t){return-1*o(e,t)}},72547:e=>{"use strict";function t(e,t,r){e instanceof RegExp&&(e=i(e,r)),t instanceof RegExp&&(t=i(t,r));var n=s(e,t,r);return n&&{start:n[0],end:n[1],pre:r.slice(0,n[0]),body:r.slice(n[0]+e.length,n[1]),post:r.slice(n[1]+t.length)}}function i(e,t){var i=t.match(e);return i?i[0]:null}function s(e,t,i){var s,r,n,o,a,c=i.indexOf(e),l=i.indexOf(t,c+1),p=c;if(c>=0&&l>0){if(e===t)return[c,l];for(s=[],n=i.length;p>=0&&!a;)p==c?(s.push(p),c=i.indexOf(e,p+1)):1==s.length?a=[s.pop(),l]:((r=s.pop())=0?c:l;s.length&&(a=[n,o])}return a}e.exports=t,t.range=s},8903:(e,t,i)=>{var s=i(46459),r=i(32361),n=i(62235),o=Function.bind,a=o.bind(o);function c(e,t,i){var s=a(n,null).apply(null,i?[t,i]:[t]);e.api={remove:s},e.remove=s,["before","error","after","wrap"].forEach((function(s){var n=i?[t,s,i]:[t,s];e[s]=e.api[s]=a(r,null).apply(null,n)}))}function l(){var e={registry:{}},t=s.bind(null,e);return c(t,e),t}var p=!1;function A(){return p||(console.warn('[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4'),p=!0),l()}A.Singular=function(){var e={registry:{}},t=s.bind(null,e,"h");return c(t,e,"h"),t}.bind(),A.Collection=l.bind(),e.exports=A,e.exports.Hook=A,e.exports.Singular=A.Singular,e.exports.Collection=A.Collection},32361:e=>{e.exports=function(e,t,i,s){var r=s;e.registry[i]||(e.registry[i]=[]),"before"===t&&(s=function(e,t){return Promise.resolve().then(r.bind(null,t)).then(e.bind(null,t))}),"after"===t&&(s=function(e,t){var i;return Promise.resolve().then(e.bind(null,t)).then((function(e){return r(i=e,t)})).then((function(){return i}))}),"error"===t&&(s=function(e,t){return Promise.resolve().then(e.bind(null,t)).catch((function(e){return r(e,t)}))}),e.registry[i].push({hook:s,orig:r})}},46459:e=>{e.exports=function e(t,i,s,r){if("function"!=typeof s)throw new Error("method for before hook must be a function");return r||(r={}),Array.isArray(i)?i.reverse().reduce((function(i,s){return e.bind(null,t,s,i,r)}),s)():Promise.resolve().then((function(){return t.registry[i]?t.registry[i].reduce((function(e,t){return t.hook.bind(null,e,r)}),s)():s(r)}))}},62235:e=>{e.exports=function(e,t,i){if(e.registry[t]){var s=e.registry[t].map((function(e){return e.orig})).indexOf(i);-1!==s&&e.registry[t].splice(s,1)}}},20276:(e,t,i)=>{"use strict";const{Buffer:s}=i(14300),r=Symbol.for("BufferList");function n(e){if(!(this instanceof n))return new n(e);n._init.call(this,e)}n._init=function(e){Object.defineProperty(this,r,{value:!0}),this._bufs=[],this.length=0,e&&this.append(e)},n.prototype._new=function(e){return new n(e)},n.prototype._offset=function(e){if(0===e)return[0,0];let t=0;for(let i=0;ithis.length||e<0)return;const t=this._offset(e);return this._bufs[t[0]][t[1]]},n.prototype.slice=function(e,t){return"number"==typeof e&&e<0&&(e+=this.length),"number"==typeof t&&t<0&&(t+=this.length),this.copy(null,0,e,t)},n.prototype.copy=function(e,t,i,r){if(("number"!=typeof i||i<0)&&(i=0),("number"!=typeof r||r>this.length)&&(r=this.length),i>=this.length)return e||s.alloc(0);if(r<=0)return e||s.alloc(0);const n=!!e,o=this._offset(i),a=r-i;let c=a,l=n&&t||0,p=o[1];if(0===i&&r===this.length){if(!n)return 1===this._bufs.length?this._bufs[0]:s.concat(this._bufs,this.length);for(let t=0;ti)){this._bufs[t].copy(e,l,p,p+c),l+=i;break}this._bufs[t].copy(e,l,p),l+=i,c-=i,p&&(p=0)}return e.length>l?e.slice(0,l):e},n.prototype.shallowSlice=function(e,t){if(e=e||0,t="number"!=typeof t?this.length:t,e<0&&(e+=this.length),t<0&&(t+=this.length),e===t)return this._new();const i=this._offset(e),s=this._offset(t),r=this._bufs.slice(i[0],s[0]+1);return 0===s[1]?r.pop():r[r.length-1]=r[r.length-1].slice(0,s[1]),0!==i[1]&&(r[0]=r[0].slice(i[1])),this._new(r)},n.prototype.toString=function(e,t,i){return this.slice(t,i).toString(e)},n.prototype.consume=function(e){if(e=Math.trunc(e),Number.isNaN(e)||e<=0)return this;for(;this._bufs.length;){if(!(e>=this._bufs[0].length)){this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift()}return this},n.prototype.duplicate=function(){const e=this._new();for(let t=0;tthis.length?this.length:t;const r=this._offset(t);let n=r[0],o=r[1];for(;n=e.length){const i=t.indexOf(e,o);if(-1!==i)return this._reverseOffset([n,i]);o=t.length-e.length+1}else{const t=this._reverseOffset([n,o]);if(this._match(t,e))return t;o++}o=0}return-1},n.prototype._match=function(e,t){if(this.length-e{"use strict";const s=i(65945).Duplex,r=i(44236),n=i(20276);function o(e){if(!(this instanceof o))return new o(e);if("function"==typeof e){this._callback=e;const t=function(e){this._callback&&(this._callback(e),this._callback=null)}.bind(this);this.on("pipe",(function(e){e.on("error",t)})),this.on("unpipe",(function(e){e.removeListener("error",t)})),e=null}n._init.call(this,e),s.call(this)}r(o,s),Object.assign(o.prototype,n.prototype),o.prototype._new=function(e){return new o(e)},o.prototype._write=function(e,t,i){this._appendBuffer(e),"function"==typeof i&&i()},o.prototype._read=function(e){if(!this.length)return this.push(null);e=Math.min(e,this.length),this.push(this.slice(0,e)),this.consume(e)},o.prototype.end=function(e){s.prototype.end.call(this,e),this._callback&&(this._callback(null,this.slice()),this._callback=null)},o.prototype._destroy=function(e,t){this._bufs.length=0,this.length=0,t(e)},o.prototype._isBufferList=function(e){return e instanceof o||e instanceof n||o.isBufferList(e)},o.isBufferList=n.isBufferList,e.exports=o,e.exports.BufferListStream=o,e.exports.BufferList=n},32722:function(e){var t;t=function(){"use strict";var e,t,i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},s={load:function(e,t,i={}){var s,r,n;for(s in t)n=t[s],i[s]=null!=(r=e[s])?r:n;return i},overwrite:function(e,t,i={}){var s,r;for(s in e)r=e[s],void 0!==t[s]&&(i[s]=r);return i}},r=class{constructor(e,t){this.incr=e,this.decr=t,this._first=null,this._last=null,this.length=0}push(e){var t;this.length++,"function"==typeof this.incr&&this.incr(),t={value:e,prev:this._last,next:null},null!=this._last?(this._last.next=t,this._last=t):this._first=this._last=t}shift(){var e;if(null!=this._first)return this.length--,"function"==typeof this.decr&&this.decr(),e=this._first.value,null!=(this._first=this._first.next)?this._first.prev=null:this._last=null,e}first(){if(null!=this._first)return this._first.value}getArray(){var e,t,i;for(e=this._first,i=[];null!=e;)i.push((t=e,e=e.next,t.value));return i}forEachShift(e){var t;for(t=this.shift();null!=t;)e(t),t=this.shift()}debug(){var e,t,i,s,r;for(e=this._first,r=[];null!=e;)r.push((t=e,e=e.next,{value:t.value,prev:null!=(i=t.prev)?i.value:void 0,next:null!=(s=t.next)?s.value:void 0}));return r}},n=class{constructor(e){if(this.instance=e,this._events={},null!=this.instance.on||null!=this.instance.once||null!=this.instance.removeAllListeners)throw new Error("An Emitter already exists for this object");this.instance.on=(e,t)=>this._addListener(e,"many",t),this.instance.once=(e,t)=>this._addListener(e,"once",t),this.instance.removeAllListeners=(e=null)=>null!=e?delete this._events[e]:this._events={}}_addListener(e,t,i){var s;return null==(s=this._events)[e]&&(s[e]=[]),this._events[e].push({cb:i,status:t}),this.instance}listenerCount(e){return null!=this._events[e]?this._events[e].length:0}async trigger(e,...t){var i,s;try{if("debug"!==e&&this.trigger("debug",`Event triggered: ${e}`,t),null==this._events[e])return;return this._events[e]=this._events[e].filter((function(e){return"none"!==e.status})),s=this._events[e].map((async e=>{var i,s;if("none"!==e.status){"once"===e.status&&(e.status="none");try{return"function"==typeof(null!=(s="function"==typeof e.cb?e.cb(...t):void 0)?s.then:void 0)?await s:s}catch(e){return i=e,this.trigger("error",i),null}}})),(await Promise.all(s)).find((function(e){return null!=e}))}catch(e){return i=e,this.trigger("error",i),null}}};e=r,t=n;var o,a,c=class extends Error{};a=s,o=c;var l,p,A=class{constructor(e,t,i,s,r,n,o,c){this.task=e,this.args=t,this.rejectOnDrop=r,this.Events=n,this._states=o,this.Promise=c,this.options=a.load(i,s),this.options.priority=this._sanitizePriority(this.options.priority),this.options.id===s.id&&(this.options.id=`${this.options.id}-${this._randomIndex()}`),this.promise=new this.Promise(((e,t)=>{this._resolve=e,this._reject=t})),this.retryCount=0}_sanitizePriority(e){var t;return(t=~~e!==e?5:e)<0?0:t>9?9:t}_randomIndex(){return Math.random().toString(36).slice(2)}doDrop({error:e,message:t="This job has been dropped by Bottleneck"}={}){return!!this._states.remove(this.options.id)&&(this.rejectOnDrop&&this._reject(null!=e?e:new o(t)),this.Events.trigger("dropped",{args:this.args,options:this.options,task:this.task,promise:this.promise}),!0)}_assertStatus(e){var t;if((t=this._states.jobStatus(this.options.id))!==e&&("DONE"!==e||null!==t))throw new o(`Invalid job status ${t}, expected ${e}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`)}doReceive(){return this._states.start(this.options.id),this.Events.trigger("received",{args:this.args,options:this.options})}doQueue(e,t){return this._assertStatus("RECEIVED"),this._states.next(this.options.id),this.Events.trigger("queued",{args:this.args,options:this.options,reachedHWM:e,blocked:t})}doRun(){return 0===this.retryCount?(this._assertStatus("QUEUED"),this._states.next(this.options.id)):this._assertStatus("EXECUTING"),this.Events.trigger("scheduled",{args:this.args,options:this.options})}async doExecute(e,t,i,s){var r,n,o;0===this.retryCount?(this._assertStatus("RUNNING"),this._states.next(this.options.id)):this._assertStatus("EXECUTING"),n={args:this.args,options:this.options,retryCount:this.retryCount},this.Events.trigger("executing",n);try{if(o=await(null!=e?e.schedule(this.options,this.task,...this.args):this.task(...this.args)),t())return this.doDone(n),await s(this.options,n),this._assertStatus("DONE"),this._resolve(o)}catch(e){return r=e,this._onFailure(r,n,t,i,s)}}doExpire(e,t,i){var s,r;return this._states.jobStatus("RUNNING"===this.options.id)&&this._states.next(this.options.id),this._assertStatus("EXECUTING"),r={args:this.args,options:this.options,retryCount:this.retryCount},s=new o(`This job timed out after ${this.options.expiration} ms.`),this._onFailure(s,r,e,t,i)}async _onFailure(e,t,i,s,r){var n,o;if(i())return null!=(n=await this.Events.trigger("failed",e,t))?(o=~~n,this.Events.trigger("retry",`Retrying ${this.options.id} after ${o} ms`,t),this.retryCount++,s(o)):(this.doDone(t),await r(this.options,t),this._assertStatus("DONE"),this._reject(e))}doDone(e){return this._assertStatus("EXECUTING"),this._states.next(this.options.id),this.Events.trigger("done",e)}};p=s,l=c;var u;u=c;var d;d=r;var h,m,g,f,E,C="2.19.5",y={version:C},v=Object.freeze({version:C,default:y}),I=()=>console.log("You must import the full version of Bottleneck in order to use this feature."),B=()=>console.log("You must import the full version of Bottleneck in order to use this feature.");E=s,h=n,g=I,m=B,f=()=>console.log("You must import the full version of Bottleneck in order to use this feature.");var w,b,Q=function(){class e{constructor(e={}){this.deleteKey=this.deleteKey.bind(this),this.limiterOptions=e,E.load(this.limiterOptions,this.defaults,this),this.Events=new h(this),this.instances={},this.Bottleneck=U,this._startAutoCleanup(),this.sharedConnection=null!=this.connection,null==this.connection&&("redis"===this.limiterOptions.datastore?this.connection=new g(Object.assign({},this.limiterOptions,{Events:this.Events})):"ioredis"===this.limiterOptions.datastore&&(this.connection=new m(Object.assign({},this.limiterOptions,{Events:this.Events}))))}key(e=""){var t;return null!=(t=this.instances[e])?t:(()=>{var t;return t=this.instances[e]=new this.Bottleneck(Object.assign(this.limiterOptions,{id:`${this.id}-${e}`,timeout:this.timeout,connection:this.connection})),this.Events.trigger("created",t,e),t})()}async deleteKey(e=""){var t,i;return i=this.instances[e],this.connection&&(t=await this.connection.__runCommand__(["del",...f.allKeys(`${this.id}-${e}`)])),null!=i&&(delete this.instances[e],await i.disconnect()),null!=i||t>0}limiters(){var e,t,i,s;for(e in i=[],t=this.instances)s=t[e],i.push({key:e,limiter:s});return i}keys(){return Object.keys(this.instances)}async clusterKeys(){var e,t,i,s,r,n,o,a;if(null==this.connection)return this.Promise.resolve(this.keys());for(r=[],e=null,a=`b_${this.id}-`.length;0!==e;)for([o,t]=await this.connection.__runCommand__(["scan",null!=e?e:0,"match",`b_${this.id}-*_settings`,"count",1e4]),e=~~o,i=0,n=t.length;i{var e,t,i,s,r,n;for(t in r=Date.now(),s=[],i=this.instances){n=i[t];try{await n._store.__groupCheck__(r)?s.push(this.deleteKey(t)):s.push(void 0)}catch(t){e=t,s.push(n.Events.trigger("error",e))}}return s}),this.timeout/2)).unref?e.unref():void 0}updateSettings(e={}){if(E.overwrite(e,this.defaults,this),E.overwrite(e,e,this.limiterOptions),null!=e.timeout)return this._startAutoCleanup()}disconnect(e=!0){var t;if(!this.sharedConnection)return null!=(t=this.connection)?t.disconnect(e):void 0}}return e.prototype.defaults={timeout:3e5,connection:null,Promise,id:"group-key"},e}.call(i);b=s,w=n;var x,k,D,S,_,R,T,F,N,L=function(){class e{constructor(e={}){this.options=e,b.load(this.options,this.defaults,this),this.Events=new w(this),this._arr=[],this._resetPromise(),this._lastFlush=Date.now()}_resetPromise(){return this._promise=new this.Promise(((e,t)=>this._resolve=e))}_flush(){return clearTimeout(this._timeout),this._lastFlush=Date.now(),this._resolve(),this.Events.trigger("batch",this._arr),this._arr=[],this._resetPromise()}add(e){var t;return this._arr.push(e),t=this._promise,this._arr.length===this.maxSize?this._flush():null!=this.maxTime&&1===this._arr.length&&(this._timeout=setTimeout((()=>this._flush()),this.maxTime)),t}}return e.prototype.defaults={maxTime:null,maxSize:null,Promise},e}.call(i),O=(x=v)&&x.default||x,M=[].splice;N=s,_=class{constructor(i){this.Events=new t(this),this._length=0,this._lists=function(){var t,s,r;for(r=[],t=1,s=i;1<=s?t<=s:t>=s;1<=s?++t:--t)r.push(new e((()=>this.incr()),(()=>this.decr())));return r}.call(this)}incr(){if(0==this._length++)return this.Events.trigger("leftzero")}decr(){if(0==--this._length)return this.Events.trigger("zero")}push(e){return this._lists[e.options.priority].push(e)}queued(e){return null!=e?this._lists[e].length:this._length}shiftAll(e){return this._lists.forEach((function(t){return t.forEachShift(e)}))}getFirst(e=this._lists){var t,i,s;for(t=0,i=e.length;t0)return s;return[]}shiftLastFrom(e){return this.getFirst(this._lists.slice(e).reverse()).shift()}},D=A,S=class{constructor(e,t,i){this.instance=e,this.storeOptions=t,this.clientId=this.instance._randomIndex(),p.load(i,i,this),this._nextRequest=this._lastReservoirRefresh=this._lastReservoirIncrease=Date.now(),this._running=0,this._done=0,this._unblockTime=0,this.ready=this.Promise.resolve(),this.clients={},this._startHeartbeat()}_startHeartbeat(){var e;return null==this.heartbeat&&(null!=this.storeOptions.reservoirRefreshInterval&&null!=this.storeOptions.reservoirRefreshAmount||null!=this.storeOptions.reservoirIncreaseInterval&&null!=this.storeOptions.reservoirIncreaseAmount)?"function"==typeof(e=this.heartbeat=setInterval((()=>{var e,t,i,s,r;if(s=Date.now(),null!=this.storeOptions.reservoirRefreshInterval&&s>=this._lastReservoirRefresh+this.storeOptions.reservoirRefreshInterval&&(this._lastReservoirRefresh=s,this.storeOptions.reservoir=this.storeOptions.reservoirRefreshAmount,this.instance._drainAll(this.computeCapacity())),null!=this.storeOptions.reservoirIncreaseInterval&&s>=this._lastReservoirIncrease+this.storeOptions.reservoirIncreaseInterval&&(({reservoirIncreaseAmount:e,reservoirIncreaseMaximum:i,reservoir:r}=this.storeOptions),this._lastReservoirIncrease=s,(t=null!=i?Math.min(e,i-r):e)>0))return this.storeOptions.reservoir+=t,this.instance._drainAll(this.computeCapacity())}),this.heartbeatInterval)).unref?e.unref():void 0:clearInterval(this.heartbeat)}async __publish__(e){return await this.yieldLoop(),this.instance.Events.trigger("message",e.toString())}async __disconnect__(e){return await this.yieldLoop(),clearInterval(this.heartbeat),this.Promise.resolve()}yieldLoop(e=0){return new this.Promise((function(t,i){return setTimeout(t,e)}))}computePenalty(){var e;return null!=(e=this.storeOptions.penalty)?e:15*this.storeOptions.minTime||5e3}async __updateSettings__(e){return await this.yieldLoop(),p.overwrite(e,e,this.storeOptions),this._startHeartbeat(),this.instance._drainAll(this.computeCapacity()),!0}async __running__(){return await this.yieldLoop(),this._running}async __queued__(){return await this.yieldLoop(),this.instance.queued()}async __done__(){return await this.yieldLoop(),this._done}async __groupCheck__(e){return await this.yieldLoop(),this._nextRequest+this.timeout=e}check(e,t){return this.conditionsCheck(e)&&this._nextRequest-t<=0}async __check__(e){var t;return await this.yieldLoop(),t=Date.now(),this.check(e,t)}async __register__(e,t,i){var s,r;return await this.yieldLoop(),s=Date.now(),this.conditionsCheck(t)?(this._running+=t,null!=this.storeOptions.reservoir&&(this.storeOptions.reservoir-=t),r=Math.max(this._nextRequest-s,0),this._nextRequest=s+r+this.storeOptions.minTime,{success:!0,wait:r,reservoir:this.storeOptions.reservoir}):{success:!1}}strategyIsBlock(){return 3===this.storeOptions.strategy}async __submit__(e,t){var i,s,r;if(await this.yieldLoop(),null!=this.storeOptions.maxConcurrent&&t>this.storeOptions.maxConcurrent)throw new l(`Impossible to add a job having a weight of ${t} to a limiter having a maxConcurrent setting of ${this.storeOptions.maxConcurrent}`);return s=Date.now(),r=null!=this.storeOptions.highWater&&e===this.storeOptions.highWater&&!this.check(t,s),(i=this.strategyIsBlock()&&(r||this.isBlocked(s)))&&(this._unblockTime=s+this.computePenalty(),this._nextRequest=this._unblockTime+this.storeOptions.minTime,this.instance._dropAllQueued()),{reachedHWM:r,blocked:i,strategy:this.storeOptions.strategy}}async __free__(e,t){return await this.yieldLoop(),this._running-=t,this._done+=t,this.instance._drainAll(this.computeCapacity()),{running:this._running}}},R=()=>console.log("You must import the full version of Bottleneck in order to use this feature."),k=n,T=class{constructor(e){this.status=e,this._jobs={},this.counts=this.status.map((function(){return 0}))}next(e){var t,i;return i=(t=this._jobs[e])+1,null!=t&&i(e[this.status[i]]=t,e)),{})}},F=class{constructor(e,t){this.schedule=this.schedule.bind(this),this.name=e,this.Promise=t,this._running=0,this._queue=new d}isEmpty(){return 0===this._queue.length}async _tryToRun(){var e,t,i,s,r,n,o;if(this._running<1&&this._queue.length>0)return this._running++,({task:o,args:e,resolve:r,reject:s}=this._queue.shift()),t=await async function(){try{return n=await o(...e),function(){return r(n)}}catch(e){return i=e,function(){return s(i)}}}(),this._running--,this._tryToRun(),t()}schedule(e,...t){var i,s,r;return r=s=null,i=new this.Promise((function(e,t){return r=e,s=t})),this._queue.push({task:e,args:t,resolve:r,reject:s}),this._tryToRun(),i}};var U=function(){class e{constructor(t={},...i){var s,r;this._addToQueue=this._addToQueue.bind(this),this._validateOptions(t,i),N.load(t,this.instanceDefaults,this),this._queues=new _(10),this._scheduled={},this._states=new T(["RECEIVED","QUEUED","RUNNING","EXECUTING"].concat(this.trackDoneStatus?["DONE"]:[])),this._limiter=null,this.Events=new k(this),this._submitLock=new F("submit",this.Promise),this._registerLock=new F("register",this.Promise),r=N.load(t,this.storeDefaults,{}),this._store=function(){if("redis"===this.datastore||"ioredis"===this.datastore||null!=this.connection)return s=N.load(t,this.redisStoreDefaults,{}),new R(this,r,s);if("local"===this.datastore)return s=N.load(t,this.localStoreDefaults,{}),new S(this,r,s);throw new e.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`)}.call(this),this._queues.on("leftzero",(()=>{var e;return null!=(e=this._store.heartbeat)&&"function"==typeof e.ref?e.ref():void 0})),this._queues.on("zero",(()=>{var e;return null!=(e=this._store.heartbeat)&&"function"==typeof e.unref?e.unref():void 0}))}_validateOptions(t,i){if(null==t||"object"!=typeof t||0!==i.length)throw new e.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1.")}ready(){return this._store.ready}clients(){return this._store.clients}channel(){return`b_${this.id}`}channel_client(){return`b_${this.id}_${this._store.clientId}`}publish(e){return this._store.__publish__(e)}disconnect(e=!0){return this._store.__disconnect__(e)}chain(e){return this._limiter=e,this}queued(e){return this._queues.queued(e)}clusterQueued(){return this._store.__queued__()}empty(){return 0===this.queued()&&this._submitLock.isEmpty()}running(){return this._store.__running__()}done(){return this._store.__done__()}jobStatus(e){return this._states.jobStatus(e)}jobs(e){return this._states.statusJobs(e)}counts(){return this._states.statusCounts()}_randomIndex(){return Math.random().toString(36).slice(2)}check(e=1){return this._store.__check__(e)}_clearGlobalState(e){return null!=this._scheduled[e]&&(clearTimeout(this._scheduled[e].expiration),delete this._scheduled[e],!0)}async _free(e,t,i,s){var r,n;try{if(({running:n}=await this._store.__free__(e,i.weight)),this.Events.trigger("debug",`Freed ${i.id}`,s),0===n&&this.empty())return this.Events.trigger("idle")}catch(e){return r=e,this.Events.trigger("error",r)}}_run(e,t,i){var s,r,n;return t.doRun(),s=this._clearGlobalState.bind(this,e),n=this._run.bind(this,e,t),r=this._free.bind(this,e,t),this._scheduled[e]={timeout:setTimeout((()=>t.doExecute(this._limiter,s,n,r)),i),expiration:null!=t.options.expiration?setTimeout((function(){return t.doExpire(s,n,r)}),i+t.options.expiration):void 0,job:t}}_drainOne(e){return this._registerLock.schedule((()=>{var t,i,s,r,n;return 0===this.queued()?this.Promise.resolve(null):(n=this._queues.getFirst(),({options:r,args:t}=s=n.first()),null!=e&&r.weight>e?this.Promise.resolve(null):(this.Events.trigger("debug",`Draining ${r.id}`,{args:t,options:r}),i=this._randomIndex(),this._store.__register__(i,r.weight,r.expiration).then((({success:e,wait:o,reservoir:a})=>{var c;return this.Events.trigger("debug",`Drained ${r.id}`,{success:e,args:t,options:r}),e?(n.shift(),(c=this.empty())&&this.Events.trigger("empty"),0===a&&this.Events.trigger("depleted",c),this._run(i,s,o),this.Promise.resolve(r.weight)):this.Promise.resolve(null)}))))}))}_drainAll(e,t=0){return this._drainOne(e).then((i=>{var s;return null!=i?(s=null!=e?e-i:e,this._drainAll(s,t+i)):this.Promise.resolve(t)})).catch((e=>this.Events.trigger("error",e)))}_dropAllQueued(e){return this._queues.shiftAll((function(t){return t.doDrop({message:e})}))}stop(t={}){var i,s;return t=N.load(t,this.stopDefaults),s=e=>{var t;return t=()=>{var t;return(t=this._states.counts)[0]+t[1]+t[2]+t[3]===e},new this.Promise(((e,i)=>t()?e():this.on("done",(()=>{if(t())return this.removeAllListeners("done"),e()}))))},i=t.dropWaitingJobs?(this._run=function(e,i){return i.doDrop({message:t.dropErrorMessage})},this._drainOne=()=>this.Promise.resolve(null),this._registerLock.schedule((()=>this._submitLock.schedule((()=>{var e,i,r;for(e in i=this._scheduled)r=i[e],"RUNNING"===this.jobStatus(r.job.options.id)&&(clearTimeout(r.timeout),clearTimeout(r.expiration),r.job.doDrop({message:t.dropErrorMessage}));return this._dropAllQueued(t.dropErrorMessage),s(0)}))))):this.schedule({priority:9,weight:0},(()=>s(1))),this._receive=function(i){return i._reject(new e.prototype.BottleneckError(t.enqueueErrorMessage))},this.stop=()=>this.Promise.reject(new e.prototype.BottleneckError("stop() has already been called")),i}async _addToQueue(t){var i,s,r,n,o,a,c;({args:i,options:n}=t);try{({reachedHWM:o,blocked:s,strategy:c}=await this._store.__submit__(this.queued(),n.weight))}catch(e){return r=e,this.Events.trigger("debug",`Could not queue ${n.id}`,{args:i,options:n,error:r}),t.doDrop({error:r}),!1}return s?(t.doDrop(),!0):o&&(null!=(a=c===e.prototype.strategy.LEAK?this._queues.shiftLastFrom(n.priority):c===e.prototype.strategy.OVERFLOW_PRIORITY?this._queues.shiftLastFrom(n.priority+1):c===e.prototype.strategy.OVERFLOW?t:void 0)&&a.doDrop(),null==a||c===e.prototype.strategy.OVERFLOW)?(null==a&&t.doDrop(),o):(t.doQueue(o,s),this._queues.push(t),await this._drainAll(),o)}_receive(t){return null!=this._states.jobStatus(t.options.id)?(t._reject(new e.prototype.BottleneckError(`A job with the same id already exists (id=${t.options.id})`)),!1):(t.doReceive(),this._submitLock.schedule(this._addToQueue,t))}submit(...e){var t,i,s,r,n,o,a;return"function"==typeof e[0]?(n=e,[i,...e]=n,[t]=M.call(e,-1),r=N.load({},this.jobDefaults)):(o=e,[r,i,...e]=o,[t]=M.call(e,-1),r=N.load(r,this.jobDefaults)),a=(...e)=>new this.Promise((function(t,s){return i(...e,(function(...e){return(null!=e[0]?s:t)(e)}))})),(s=new D(a,e,r,this.jobDefaults,this.rejectOnDrop,this.Events,this._states,this.Promise)).promise.then((function(e){return"function"==typeof t?t(...e):void 0})).catch((function(e){return Array.isArray(e)?"function"==typeof t?t(...e):void 0:"function"==typeof t?t(e):void 0})),this._receive(s)}schedule(...e){var t,i,s;return"function"==typeof e[0]?([s,...e]=e,i={}):[i,s,...e]=e,t=new D(s,e,i,this.jobDefaults,this.rejectOnDrop,this.Events,this._states,this.Promise),this._receive(t),t.promise}wrap(e){var t,i;return t=this.schedule.bind(this),(i=function(...i){return t(e.bind(this),...i)}).withOptions=function(i,...s){return t(i,e,...s)},i}async updateSettings(e={}){return await this._store.__updateSettings__(N.overwrite(e,this.storeDefaults)),N.overwrite(e,this.instanceDefaults,this),this}currentReservoir(){return this._store.__currentReservoir__()}incrementReservoir(e=0){return this._store.__incrementReservoir__(e)}}return e.default=e,e.Events=k,e.version=e.prototype.version=O.version,e.strategy=e.prototype.strategy={LEAK:1,OVERFLOW:2,OVERFLOW_PRIORITY:4,BLOCK:3},e.BottleneckError=e.prototype.BottleneckError=c,e.Group=e.prototype.Group=Q,e.RedisConnection=e.prototype.RedisConnection=I,e.IORedisConnection=e.prototype.IORedisConnection=B,e.Batcher=e.prototype.Batcher=L,e.prototype.jobDefaults={priority:5,weight:1,expiration:null,id:""},e.prototype.storeDefaults={maxConcurrent:null,minTime:0,highWater:null,strategy:e.prototype.strategy.LEAK,penalty:null,reservoir:null,reservoirRefreshInterval:null,reservoirRefreshAmount:null,reservoirIncreaseInterval:null,reservoirIncreaseAmount:null,reservoirIncreaseMaximum:null},e.prototype.localStoreDefaults={Promise,timeout:null,heartbeatInterval:250},e.prototype.redisStoreDefaults={Promise,timeout:null,heartbeatInterval:5e3,clientTimeout:1e4,Redis:null,clientOptions:{},clusterNodes:null,clearDatastore:!1,connection:null},e.prototype.instanceDefaults={datastore:"local",connection:null,id:"",rejectOnDrop:!0,trackDoneStatus:!1,Promise},e.prototype.stopDefaults={enqueueErrorMessage:"This limiter has been stopped and cannot accept new jobs.",dropWaitingJobs:!0,dropErrorMessage:"This limiter has been stopped."},e}.call(i);return U},e.exports=t()},58389:(e,t,i)=>{var s=i(72547);e.exports=function(e){return e?("{}"===e.substr(0,2)&&(e="\\{\\}"+e.substr(2)),g(function(e){return e.split("\\\\").join(r).split("\\{").join(n).split("\\}").join(o).split("\\,").join(a).split("\\.").join(c)}(e),!0).map(p)):[]};var r="\0SLASH"+Math.random()+"\0",n="\0OPEN"+Math.random()+"\0",o="\0CLOSE"+Math.random()+"\0",a="\0COMMA"+Math.random()+"\0",c="\0PERIOD"+Math.random()+"\0";function l(e){return parseInt(e,10)==e?parseInt(e,10):e.charCodeAt(0)}function p(e){return e.split(r).join("\\").split(n).join("{").split(o).join("}").split(a).join(",").split(c).join(".")}function A(e){if(!e)return[""];var t=[],i=s("{","}",e);if(!i)return e.split(",");var r=i.pre,n=i.body,o=i.post,a=r.split(",");a[a.length-1]+="{"+n+"}";var c=A(o);return o.length&&(a[a.length-1]+=c.shift(),a.push.apply(a,c)),t.push.apply(t,a),t}function u(e){return"{"+e+"}"}function d(e){return/^-?0\d/.test(e)}function h(e,t){return e<=t}function m(e,t){return e>=t}function g(e,t){var i=[],r=s("{","}",e);if(!r)return[e];var n=r.pre,a=r.post.length?g(r.post,!1):[""];if(/\$$/.test(r.pre))for(var c=0;c=0;if(!v&&!I)return r.post.match(/,.*\}/)?g(e=r.pre+"{"+r.body+o+r.post):[e];if(v)f=r.body.split(/\.\./);else if(1===(f=A(r.body)).length&&1===(f=g(f[0],!1).map(u)).length)return a.map((function(e){return r.pre+f[0]+e}));if(v){var B=l(f[0]),w=l(f[1]),b=Math.max(f[0].length,f[1].length),Q=3==f.length?Math.abs(l(f[2])):1,x=h;w0){var R=new Array(_+1).join("0");S=D<0?"-"+R+S.slice(1):R+S}}E.push(S)}}else{E=[];for(var T=0;T{e.exports=function(e){return new Buffer(e).toString("base64")}},47309:(e,t,i)=>{"use strict";const s=i(78413),{stdout:r,stderr:n}=i(10447),{stringReplaceAll:o,stringEncaseCRLFWithFirstIndex:a}=i(63370),{isArray:c}=Array,l=["ansi","ansi","ansi256","ansi16m"],p=Object.create(null);class A{constructor(e){return u(e)}}const u=e=>{const t={};return((e,t={})=>{if(t.level&&!(Number.isInteger(t.level)&&t.level>=0&&t.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");const i=r?r.level:0;e.level=void 0===t.level?i:t.level})(t,e),t.template=(...e)=>y(t.template,...e),Object.setPrototypeOf(t,d.prototype),Object.setPrototypeOf(t.template,t),t.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},t.template.Instance=A,t.template};function d(e){return u(e)}for(const[e,t]of Object.entries(s))p[e]={get(){const i=f(this,g(t.open,t.close,this._styler),this._isEmpty);return Object.defineProperty(this,e,{value:i}),i}};p.visible={get(){const e=f(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:e}),e}};const h=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(const e of h)p[e]={get(){const{level:t}=this;return function(...i){const r=g(s.color[l[t]][e](...i),s.color.close,this._styler);return f(this,r,this._isEmpty)}}};for(const e of h)p["bg"+e[0].toUpperCase()+e.slice(1)]={get(){const{level:t}=this;return function(...i){const r=g(s.bgColor[l[t]][e](...i),s.bgColor.close,this._styler);return f(this,r,this._isEmpty)}}};const m=Object.defineProperties((()=>{}),{...p,level:{enumerable:!0,get(){return this._generator.level},set(e){this._generator.level=e}}}),g=(e,t,i)=>{let s,r;return void 0===i?(s=e,r=t):(s=i.openAll+e,r=t+i.closeAll),{open:e,close:t,openAll:s,closeAll:r,parent:i}},f=(e,t,i)=>{const s=(...e)=>c(e[0])&&c(e[0].raw)?E(s,y(s,...e)):E(s,1===e.length?""+e[0]:e.join(" "));return Object.setPrototypeOf(s,m),s._generator=e,s._styler=t,s._isEmpty=i,s},E=(e,t)=>{if(e.level<=0||!t)return e._isEmpty?"":t;let i=e._styler;if(void 0===i)return t;const{openAll:s,closeAll:r}=i;if(-1!==t.indexOf(""))for(;void 0!==i;)t=o(t,i.close,i.open),i=i.parent;const n=t.indexOf("\n");return-1!==n&&(t=a(t,r,s,n)),s+t+r};let C;const y=(e,...t)=>{const[s]=t;if(!c(s)||!c(s.raw))return t.join(" ");const r=t.slice(1),n=[s.raw[0]];for(let e=1;e{"use strict";const t=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,i=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,s=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,r=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi,n=new Map([["n","\n"],["r","\r"],["t","\t"],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e",""],["a",""]]);function o(e){const t="u"===e[0],i="{"===e[1];return t&&!i&&5===e.length||"x"===e[0]&&3===e.length?String.fromCharCode(parseInt(e.slice(1),16)):t&&i?String.fromCodePoint(parseInt(e.slice(2,-1),16)):n.get(e)||e}function a(e,t){const i=[],n=t.trim().split(/\s*,\s*/g);let a;for(const t of n){const n=Number(t);if(Number.isNaN(n)){if(!(a=t.match(s)))throw new Error(`Invalid Chalk template style argument: ${t} (in style '${e}')`);i.push(a[2].replace(r,((e,t,i)=>t?o(t):i)))}else i.push(n)}return i}function c(e){i.lastIndex=0;const t=[];let s;for(;null!==(s=i.exec(e));){const e=s[1];if(s[2]){const i=a(e,s[2]);t.push([e].concat(i))}else t.push([e])}return t}function l(e,t){const i={};for(const e of t)for(const t of e.styles)i[t[0]]=e.inverse?null:t.slice(1);let s=e;for(const[e,t]of Object.entries(i))if(Array.isArray(t)){if(!(e in s))throw new Error(`Unknown Chalk style: ${e}`);s=t.length>0?s[e](...t):s[e]}return s}e.exports=(e,i)=>{const s=[],r=[];let n=[];if(i.replace(t,((t,i,a,p,A,u)=>{if(i)n.push(o(i));else if(p){const t=n.join("");n=[],r.push(0===s.length?t:l(e,s)(t)),s.push({inverse:a,styles:c(p)})}else if(A){if(0===s.length)throw new Error("Found extraneous } in Chalk template literal");r.push(l(e,s)(n.join(""))),n=[],s.pop()}else n.push(u)})),r.push(n.join("")),s.length>0){const e=`Chalk template literal is missing ${s.length} closing bracket${1===s.length?"":"s"} (\`}\`)`;throw new Error(e)}return r.join("")}},63370:e=>{"use strict";e.exports={stringReplaceAll:(e,t,i)=>{let s=e.indexOf(t);if(-1===s)return e;const r=t.length;let n=0,o="";do{o+=e.substr(n,s-n)+t+i,n=s+r,s=e.indexOf(t,n)}while(-1!==s);return o+=e.substr(n),o},stringEncaseCRLFWithFirstIndex:(e,t,i,s)=>{let r=0,n="";do{const o="\r"===e[s-1];n+=e.substr(r,(o?s-1:s)-r)+t+(o?"\r\n":"\n")+i,r=s+1,s=e.indexOf("\n",r)}while(-1!==s);return n+=e.substr(r),n}}},53072:(e,t,i)=>{"use strict";const s=i(22037),r=/\s+at.*(?:\(|\s)(.*)\)?/,n=/^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:babel-polyfill|pirates)\/.*)?\w+)\.js:\d+:\d+)|native)/,o=void 0===s.homedir?"":s.homedir();e.exports=(e,t)=>(t=Object.assign({pretty:!1},t),e.replace(/\\/g,"/").split("\n").filter((e=>{const t=e.match(r);if(null===t||!t[1])return!0;const i=t[1];return!i.includes(".app/Contents/Resources/electron.asar")&&!i.includes(".app/Contents/Resources/default_app.asar")&&!n.test(i)})).filter((e=>""!==e.trim())).map((e=>t.pretty?e.replace(r,((e,t)=>e.replace(t,t.replace(o,"~")))):e)).join("\n"))},55693:(e,t,i)=>{"use strict";const s=i(60350);let r=!1;t.show=(e=process.stderr)=>{e.isTTY&&(r=!1,e.write("[?25h"))},t.hide=(e=process.stderr)=>{e.isTTY&&(s(),r=!0,e.write("[?25l"))},t.toggle=(e,i)=>{void 0!==e&&(r=e),r?t.show(i):t.hide(i)}},60881:(e,t,i)=>{"use strict";const s=Object.assign({},i(36432)),r=Object.keys(s);Object.defineProperty(s,"random",{get(){const e=Math.floor(Math.random()*r.length),t=r[e];return s[t]}}),e.exports=s},91969:(e,t,i)=>{var s=i(27072),r=i(34045),n=r.repeat,o=r.truncate,a=r.pad;function c(e){if(this.options=r.options({chars:{top:"─","top-mid":"┬","top-left":"┌","top-right":"┐",bottom:"─","bottom-mid":"┴","bottom-left":"└","bottom-right":"┘",left:"│","left-mid":"├",mid:"─","mid-mid":"┼",right:"│","right-mid":"┤",middle:"│"},truncate:"…",colWidths:[],colAligns:[],style:{"padding-left":1,"padding-right":1,head:["red"],border:["grey"],compact:!1},head:[]},e),e&&e.rows)for(var t=0;tr&&(r=n),s.push({contents:i,height:n})}));var c=new Array(r);s.forEach((function(e,s){e.contents.forEach((function(e,r){c[r]||(c[r]=[]),(i||a&&0===s&&t.style.head)&&(e=C(t.style.head,e)),c[r].push(e)}));for(var n=e.height,o=r;n0&&(p+="\n"+C(t.style.border,l.left)),p+=e.join(C(t.style.border,l.middle))+C(t.style.border,l.right)})),C(t.style.border,l.left)+p}function C(e,t){return t?(e.forEach((function(e){t=s[e](t)})),t):""}function y(e,s){e=String("object"==typeof e&&e.text?e.text:e);var c=r.strlen(e),l=A[s]-(i["padding-left"]||0)-(i["padding-right"]||0),u=t.colAligns[s]||"left";return n(" ",i["padding-left"]||0)+(c==l?e:c{t.repeat=function(e,t){return Array(t+1).join(e)},t.pad=function(e,t,i,s){if(t+1>=e.length)switch(s){case"left":e=Array(t+1-e.length).join(i)+e;break;case"both":var r=Math.ceil((padlen=t-e.length)/2),n=padlen-r;e=Array(n+1).join(i)+e+Array(r+1).join(i);break;default:e+=Array(t+1-e.length).join(i)}return e},t.truncate=function(e,t,i){return i=i||"…",e.length>=t?e.substr(0,t-i.length)+i:e},t.options=function e(t,i){for(var s in i)"__proto__"!==s&&"constructor"!==s&&"prototype"!==s&&(i[s]&&i[s].constructor&&i[s].constructor===Object?(t[s]=t[s]||{},e(t[s],i[s])):t[s]=i[s]);return t},t.strlen=function(e){return(""+e).replace(/\u001b\[(?:\d*;){0,5}\d*m/g,"").split("\n").reduce((function(e,t){return t.length>e?t.length:e}),0)}},54256:e=>{var t=function(){"use strict";function e(t,s,r,n){"object"==typeof s&&(r=s.depth,n=s.prototype,s.filter,s=s.circular);var o=[],a=[],c="undefined"!=typeof Buffer;return void 0===s&&(s=!0),void 0===r&&(r=1/0),function t(r,l){if(null===r)return null;if(0==l)return r;var p,A;if("object"!=typeof r)return r;if(e.__isArray(r))p=[];else if(e.__isRegExp(r))p=new RegExp(r.source,i(r)),r.lastIndex&&(p.lastIndex=r.lastIndex);else if(e.__isDate(r))p=new Date(r.getTime());else{if(c&&Buffer.isBuffer(r))return p=Buffer.allocUnsafe?Buffer.allocUnsafe(r.length):new Buffer(r.length),r.copy(p),p;void 0===n?(A=Object.getPrototypeOf(r),p=Object.create(A)):(p=Object.create(n),A=n)}if(s){var u=o.indexOf(r);if(-1!=u)return a[u];o.push(r),a.push(p)}for(var d in r){var h;A&&(h=Object.getOwnPropertyDescriptor(A,d)),h&&null==h.set||(p[d]=t(r[d],l-1))}return p}(t,r)}function t(e){return Object.prototype.toString.call(e)}function i(e){var t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),t}return e.clonePrototype=function(e){if(null===e)return null;var t=function(){};return t.prototype=e,new t},e.__objToStr=t,e.__isDate=function(e){return"object"==typeof e&&"[object Date]"===t(e)},e.__isArray=function(e){return"object"==typeof e&&"[object Array]"===t(e)},e.__isRegExp=function(e){return"object"==typeof e&&"[object RegExp]"===t(e)},e.__getRegExpFlags=i,e}();e.exports&&(e.exports=t)},38097:(e,t,i)=>{const s=i(61821),r={};for(const e of Object.keys(s))r[s[e]]=e;const n={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};e.exports=n;for(const e of Object.keys(n)){if(!("channels"in n[e]))throw new Error("missing channels property: "+e);if(!("labels"in n[e]))throw new Error("missing channel labels property: "+e);if(n[e].labels.length!==n[e].channels)throw new Error("channel and label counts mismatch: "+e);const{channels:t,labels:i}=n[e];delete n[e].channels,delete n[e].labels,Object.defineProperty(n[e],"channels",{value:t}),Object.defineProperty(n[e],"labels",{value:i})}n.rgb.hsl=function(e){const t=e[0]/255,i=e[1]/255,s=e[2]/255,r=Math.min(t,i,s),n=Math.max(t,i,s),o=n-r;let a,c;n===r?a=0:t===n?a=(i-s)/o:i===n?a=2+(s-t)/o:s===n&&(a=4+(t-i)/o),a=Math.min(60*a,360),a<0&&(a+=360);const l=(r+n)/2;return c=n===r?0:l<=.5?o/(n+r):o/(2-n-r),[a,100*c,100*l]},n.rgb.hsv=function(e){let t,i,s,r,n;const o=e[0]/255,a=e[1]/255,c=e[2]/255,l=Math.max(o,a,c),p=l-Math.min(o,a,c),A=function(e){return(l-e)/6/p+.5};return 0===p?(r=0,n=0):(n=p/l,t=A(o),i=A(a),s=A(c),o===l?r=s-i:a===l?r=1/3+t-s:c===l&&(r=2/3+i-t),r<0?r+=1:r>1&&(r-=1)),[360*r,100*n,100*l]},n.rgb.hwb=function(e){const t=e[0],i=e[1];let s=e[2];const r=n.rgb.hsl(e)[0],o=1/255*Math.min(t,Math.min(i,s));return s=1-1/255*Math.max(t,Math.max(i,s)),[r,100*o,100*s]},n.rgb.cmyk=function(e){const t=e[0]/255,i=e[1]/255,s=e[2]/255,r=Math.min(1-t,1-i,1-s);return[100*((1-t-r)/(1-r)||0),100*((1-i-r)/(1-r)||0),100*((1-s-r)/(1-r)||0),100*r]},n.rgb.keyword=function(e){const t=r[e];if(t)return t;let i,n=1/0;for(const t of Object.keys(s)){const r=(a=s[t],((o=e)[0]-a[0])**2+(o[1]-a[1])**2+(o[2]-a[2])**2);r.04045?((t+.055)/1.055)**2.4:t/12.92,i=i>.04045?((i+.055)/1.055)**2.4:i/12.92,s=s>.04045?((s+.055)/1.055)**2.4:s/12.92,[100*(.4124*t+.3576*i+.1805*s),100*(.2126*t+.7152*i+.0722*s),100*(.0193*t+.1192*i+.9505*s)]},n.rgb.lab=function(e){const t=n.rgb.xyz(e);let i=t[0],s=t[1],r=t[2];return i/=95.047,s/=100,r/=108.883,i=i>.008856?i**(1/3):7.787*i+16/116,s=s>.008856?s**(1/3):7.787*s+16/116,r=r>.008856?r**(1/3):7.787*r+16/116,[116*s-16,500*(i-s),200*(s-r)]},n.hsl.rgb=function(e){const t=e[0]/360,i=e[1]/100,s=e[2]/100;let r,n,o;if(0===i)return o=255*s,[o,o,o];r=s<.5?s*(1+i):s+i-s*i;const a=2*s-r,c=[0,0,0];for(let e=0;e<3;e++)n=t+1/3*-(e-1),n<0&&n++,n>1&&n--,o=6*n<1?a+6*(r-a)*n:2*n<1?r:3*n<2?a+(r-a)*(2/3-n)*6:a,c[e]=255*o;return c},n.hsl.hsv=function(e){const t=e[0];let i=e[1]/100,s=e[2]/100,r=i;const n=Math.max(s,.01);return s*=2,i*=s<=1?s:2-s,r*=n<=1?n:2-n,[t,100*(0===s?2*r/(n+r):2*i/(s+i)),(s+i)/2*100]},n.hsv.rgb=function(e){const t=e[0]/60,i=e[1]/100;let s=e[2]/100;const r=Math.floor(t)%6,n=t-Math.floor(t),o=255*s*(1-i),a=255*s*(1-i*n),c=255*s*(1-i*(1-n));switch(s*=255,r){case 0:return[s,c,o];case 1:return[a,s,o];case 2:return[o,s,c];case 3:return[o,a,s];case 4:return[c,o,s];case 5:return[s,o,a]}},n.hsv.hsl=function(e){const t=e[0],i=e[1]/100,s=e[2]/100,r=Math.max(s,.01);let n,o;o=(2-i)*s;const a=(2-i)*r;return n=i*r,n/=a<=1?a:2-a,n=n||0,o/=2,[t,100*n,100*o]},n.hwb.rgb=function(e){const t=e[0]/360;let i=e[1]/100,s=e[2]/100;const r=i+s;let n;r>1&&(i/=r,s/=r);const o=Math.floor(6*t),a=1-s;n=6*t-o,0!=(1&o)&&(n=1-n);const c=i+n*(a-i);let l,p,A;switch(o){default:case 6:case 0:l=a,p=c,A=i;break;case 1:l=c,p=a,A=i;break;case 2:l=i,p=a,A=c;break;case 3:l=i,p=c,A=a;break;case 4:l=c,p=i,A=a;break;case 5:l=a,p=i,A=c}return[255*l,255*p,255*A]},n.cmyk.rgb=function(e){const t=e[0]/100,i=e[1]/100,s=e[2]/100,r=e[3]/100;return[255*(1-Math.min(1,t*(1-r)+r)),255*(1-Math.min(1,i*(1-r)+r)),255*(1-Math.min(1,s*(1-r)+r))]},n.xyz.rgb=function(e){const t=e[0]/100,i=e[1]/100,s=e[2]/100;let r,n,o;return r=3.2406*t+-1.5372*i+-.4986*s,n=-.9689*t+1.8758*i+.0415*s,o=.0557*t+-.204*i+1.057*s,r=r>.0031308?1.055*r**(1/2.4)-.055:12.92*r,n=n>.0031308?1.055*n**(1/2.4)-.055:12.92*n,o=o>.0031308?1.055*o**(1/2.4)-.055:12.92*o,r=Math.min(Math.max(0,r),1),n=Math.min(Math.max(0,n),1),o=Math.min(Math.max(0,o),1),[255*r,255*n,255*o]},n.xyz.lab=function(e){let t=e[0],i=e[1],s=e[2];return t/=95.047,i/=100,s/=108.883,t=t>.008856?t**(1/3):7.787*t+16/116,i=i>.008856?i**(1/3):7.787*i+16/116,s=s>.008856?s**(1/3):7.787*s+16/116,[116*i-16,500*(t-i),200*(i-s)]},n.lab.xyz=function(e){let t,i,s;i=(e[0]+16)/116,t=e[1]/500+i,s=i-e[2]/200;const r=i**3,n=t**3,o=s**3;return i=r>.008856?r:(i-16/116)/7.787,t=n>.008856?n:(t-16/116)/7.787,s=o>.008856?o:(s-16/116)/7.787,t*=95.047,i*=100,s*=108.883,[t,i,s]},n.lab.lch=function(e){const t=e[0],i=e[1],s=e[2];let r;return r=360*Math.atan2(s,i)/2/Math.PI,r<0&&(r+=360),[t,Math.sqrt(i*i+s*s),r]},n.lch.lab=function(e){const t=e[0],i=e[1],s=e[2]/360*2*Math.PI;return[t,i*Math.cos(s),i*Math.sin(s)]},n.rgb.ansi16=function(e,t=null){const[i,s,r]=e;let o=null===t?n.rgb.hsv(e)[2]:t;if(o=Math.round(o/50),0===o)return 30;let a=30+(Math.round(r/255)<<2|Math.round(s/255)<<1|Math.round(i/255));return 2===o&&(a+=60),a},n.hsv.ansi16=function(e){return n.rgb.ansi16(n.hsv.rgb(e),e[2])},n.rgb.ansi256=function(e){const t=e[0],i=e[1],s=e[2];return t===i&&i===s?t<8?16:t>248?231:Math.round((t-8)/247*24)+232:16+36*Math.round(t/255*5)+6*Math.round(i/255*5)+Math.round(s/255*5)},n.ansi16.rgb=function(e){let t=e%10;if(0===t||7===t)return e>50&&(t+=3.5),t=t/10.5*255,[t,t,t];const i=.5*(1+~~(e>50));return[(1&t)*i*255,(t>>1&1)*i*255,(t>>2&1)*i*255]},n.ansi256.rgb=function(e){if(e>=232){const t=10*(e-232)+8;return[t,t,t]}let t;return e-=16,[Math.floor(e/36)/5*255,Math.floor((t=e%36)/6)/5*255,t%6/5*255]},n.rgb.hex=function(e){const t=(((255&Math.round(e[0]))<<16)+((255&Math.round(e[1]))<<8)+(255&Math.round(e[2]))).toString(16).toUpperCase();return"000000".substring(t.length)+t},n.hex.rgb=function(e){const t=e.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!t)return[0,0,0];let i=t[0];3===t[0].length&&(i=i.split("").map((e=>e+e)).join(""));const s=parseInt(i,16);return[s>>16&255,s>>8&255,255&s]},n.rgb.hcg=function(e){const t=e[0]/255,i=e[1]/255,s=e[2]/255,r=Math.max(Math.max(t,i),s),n=Math.min(Math.min(t,i),s),o=r-n;let a,c;return a=o<1?n/(1-o):0,c=o<=0?0:r===t?(i-s)/o%6:r===i?2+(s-t)/o:4+(t-i)/o,c/=6,c%=1,[360*c,100*o,100*a]},n.hsl.hcg=function(e){const t=e[1]/100,i=e[2]/100,s=i<.5?2*t*i:2*t*(1-i);let r=0;return s<1&&(r=(i-.5*s)/(1-s)),[e[0],100*s,100*r]},n.hsv.hcg=function(e){const t=e[1]/100,i=e[2]/100,s=t*i;let r=0;return s<1&&(r=(i-s)/(1-s)),[e[0],100*s,100*r]},n.hcg.rgb=function(e){const t=e[0]/360,i=e[1]/100,s=e[2]/100;if(0===i)return[255*s,255*s,255*s];const r=[0,0,0],n=t%1*6,o=n%1,a=1-o;let c=0;switch(Math.floor(n)){case 0:r[0]=1,r[1]=o,r[2]=0;break;case 1:r[0]=a,r[1]=1,r[2]=0;break;case 2:r[0]=0,r[1]=1,r[2]=o;break;case 3:r[0]=0,r[1]=a,r[2]=1;break;case 4:r[0]=o,r[1]=0,r[2]=1;break;default:r[0]=1,r[1]=0,r[2]=a}return c=(1-i)*s,[255*(i*r[0]+c),255*(i*r[1]+c),255*(i*r[2]+c)]},n.hcg.hsv=function(e){const t=e[1]/100,i=t+e[2]/100*(1-t);let s=0;return i>0&&(s=t/i),[e[0],100*s,100*i]},n.hcg.hsl=function(e){const t=e[1]/100,i=e[2]/100*(1-t)+.5*t;let s=0;return i>0&&i<.5?s=t/(2*i):i>=.5&&i<1&&(s=t/(2*(1-i))),[e[0],100*s,100*i]},n.hcg.hwb=function(e){const t=e[1]/100,i=t+e[2]/100*(1-t);return[e[0],100*(i-t),100*(1-i)]},n.hwb.hcg=function(e){const t=e[1]/100,i=1-e[2]/100,s=i-t;let r=0;return s<1&&(r=(i-s)/(1-s)),[e[0],100*s,100*r]},n.apple.rgb=function(e){return[e[0]/65535*255,e[1]/65535*255,e[2]/65535*255]},n.rgb.apple=function(e){return[e[0]/255*65535,e[1]/255*65535,e[2]/255*65535]},n.gray.rgb=function(e){return[e[0]/100*255,e[0]/100*255,e[0]/100*255]},n.gray.hsl=function(e){return[0,0,e[0]]},n.gray.hsv=n.gray.hsl,n.gray.hwb=function(e){return[0,100,e[0]]},n.gray.cmyk=function(e){return[0,0,0,e[0]]},n.gray.lab=function(e){return[e[0],0,0]},n.gray.hex=function(e){const t=255&Math.round(e[0]/100*255),i=((t<<16)+(t<<8)+t).toString(16).toUpperCase();return"000000".substring(i.length)+i},n.rgb.gray=function(e){return[(e[0]+e[1]+e[2])/3/255*100]}},60398:(e,t,i)=>{const s=i(38097),r=i(14657),n={};Object.keys(s).forEach((e=>{n[e]={},Object.defineProperty(n[e],"channels",{value:s[e].channels}),Object.defineProperty(n[e],"labels",{value:s[e].labels});const t=r(e);Object.keys(t).forEach((i=>{const s=t[i];n[e][i]=function(e){const t=function(...t){const i=t[0];if(null==i)return i;i.length>1&&(t=i);const s=e(t);if("object"==typeof s)for(let e=s.length,t=0;t1&&(t=i),e(t))};return"conversion"in e&&(t.conversion=e.conversion),t}(s)}))})),e.exports=n},14657:(e,t,i)=>{const s=i(38097);function r(e,t){return function(i){return t(e(i))}}function n(e,t){const i=[t[e].parent,e];let n=s[t[e].parent][e],o=t[e].parent;for(;t[o].parent;)i.unshift(t[o].parent),n=r(s[t[o].parent][o],n),o=t[o].parent;return n.conversion=i,n}e.exports=function(e){const t=function(e){const t=function(){const e={},t=Object.keys(s);for(let i=t.length,s=0;s{"use strict";e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},92604:(e,t,i)=>{var s={};e.exports=s,s.themes={};var r=s.styles=i(76375),n=Object.defineProperties;s.supportsColor=i(33578),void 0===s.enabled&&(s.enabled=s.supportsColor),s.stripColors=s.strip=function(e){return(""+e).replace(/\x1B\[\d+m/g,"")},s.stylize=function(e,t){return r[t].open+e+r[t].close};var o=/[|\\{}()[\]^$+*?.]/g;function a(e){var t=function e(){return A.apply(e,arguments)};return t._styles=e,t.__proto__=p,t}var c,l=(c={},r.grey=r.gray,Object.keys(r).forEach((function(e){r[e].closeRe=new RegExp(function(e){if("string"!=typeof e)throw new TypeError("Expected a string");return e.replace(o,"\\$&")}(r[e].close),"g"),c[e]={get:function(){return a(this._styles.concat(e))}}})),c),p=n((function(){}),l);function A(){var e=arguments,t=e.length,i=0!==t&&String(arguments[0]);if(t>1)for(var n=1;n{e.exports=function(e,t){var i="";e=(e=e||"Run the trap, drop the bass").split("");var s={a:["@","Ą","Ⱥ","Ʌ","Δ","Λ","Д"],b:["ß","Ɓ","Ƀ","ɮ","β","฿"],c:["©","Ȼ","Ͼ"],d:["Ð","Ɗ","Ԁ","ԁ","Ԃ","ԃ"],e:["Ë","ĕ","Ǝ","ɘ","Σ","ξ","Ҽ","੬"],f:["Ӻ"],g:["ɢ"],h:["Ħ","ƕ","Ң","Һ","Ӈ","Ԋ"],i:["༏"],j:["Ĵ"],k:["ĸ","Ҡ","Ӄ","Ԟ"],l:["Ĺ"],m:["ʍ","Ӎ","ӎ","Ԡ","ԡ","൩"],n:["Ñ","ŋ","Ɲ","Ͷ","Π","Ҋ"],o:["Ø","õ","ø","Ǿ","ʘ","Ѻ","ם","۝","๏"],p:["Ƿ","Ҏ"],q:["্"],r:["®","Ʀ","Ȑ","Ɍ","ʀ","Я"],s:["§","Ϟ","ϟ","Ϩ"],t:["Ł","Ŧ","ͳ"],u:["Ʊ","Ս"],v:["ט"],w:["Ш","Ѡ","Ѽ","൰"],x:["Ҳ","Ӿ","Ӽ","ӽ"],y:["¥","Ұ","Ӌ"],z:["Ƶ","ɀ"]};return e.forEach((function(e){e=e.toLowerCase();var t=s[e]||[" "],r=Math.floor(Math.random()*t.length);i+=void 0!==s[e]?s[e][r]:e})),i}},16893:e=>{e.exports=function(e,t){e=e||" he is here ";var i={up:["̍","̎","̄","̅","̿","̑","̆","̐","͒","͗","͑","̇","̈","̊","͂","̓","̈","͊","͋","͌","̃","̂","̌","͐","̀","́","̋","̏","̒","̓","̔","̽","̉","ͣ","ͤ","ͥ","ͦ","ͧ","ͨ","ͩ","ͪ","ͫ","ͬ","ͭ","ͮ","ͯ","̾","͛","͆","̚"],down:["̖","̗","̘","̙","̜","̝","̞","̟","̠","̤","̥","̦","̩","̪","̫","̬","̭","̮","̯","̰","̱","̲","̳","̹","̺","̻","̼","ͅ","͇","͈","͉","͍","͎","͓","͔","͕","͖","͙","͚","̣"],mid:["̕","̛","̀","́","͘","̡","̢","̧","̨","̴","̵","̶","͜","͝","͞","͟","͠","͢","̸","̷","͡"," ҉"]},s=[].concat(i.up,i.down,i.mid);function r(e){return Math.floor(Math.random()*e)}function n(e){var t=!1;return s.filter((function(i){t=i===e})),t}return function(e,t){var s,o,a="";for(o in(t=t||{}).up=t.up||!0,t.mid=t.mid||!0,t.down=t.down||!0,t.size=t.size||"maxi",e=e.split(""))if(!n(o)){switch(a+=e[o],s={up:0,down:0,mid:0},t.size){case"mini":s.up=r(8),s.min=r(2),s.down=r(8);break;case"maxi":s.up=r(16)+3,s.min=r(4)+1,s.down=r(64)+3;break;default:s.up=r(8)+1,s.mid=r(6)/2,s.down=r(8)+1}var c=["up","mid","down"];for(var l in c)for(var p=c[l],A=0;A<=s[p];A++)t[p]&&(a+=i[p][r(i[p].length)])}return a}(e)}},70418:(e,t,i)=>{var s=i(92604);e.exports=function(e,t,i){if(" "===e)return e;switch(t%3){case 0:return s.red(e);case 1:return s.white(e);case 2:return s.blue(e)}}},22430:(e,t,i)=>{var s,r=i(92604);e.exports=(s=["red","yellow","green","blue","magenta"],function(e,t,i){return" "===e?e:r[s[t++%s.length]](e)})},35041:(e,t,i)=>{var s,r=i(92604);e.exports=(s=["underline","inverse","grey","yellow","red","green","blue","white","cyan","magenta"],function(e,t,i){return" "===e?e:r[s[Math.round(Math.random()*(s.length-1))]](e)})},76492:(e,t,i)=>{var s=i(92604);e.exports=function(e,t,i){return t%2==0?e:s.inverse(e)}},76375:e=>{var t={};e.exports=t;var i={reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29],black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],gray:[90,39],grey:[90,39],bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],blackBG:[40,49],redBG:[41,49],greenBG:[42,49],yellowBG:[43,49],blueBG:[44,49],magentaBG:[45,49],cyanBG:[46,49],whiteBG:[47,49]};Object.keys(i).forEach((function(e){var s=i[e],r=t[e]=[];r.open="["+s[0]+"m",r.close="["+s[1]+"m"}))},33578:e=>{var t=process.argv;e.exports=-1===t.indexOf("--no-color")&&-1===t.indexOf("--color=false")&&(-1!==t.indexOf("--color")||-1!==t.indexOf("--color=true")||-1!==t.indexOf("--color=always")||!(process.stdout&&!process.stdout.isTTY)&&("win32"===process.platform||"COLORTERM"in process.env||"dumb"!==process.env.TERM&&!!/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(process.env.TERM)))},28130:e=>{function t(e){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}t.keys=()=>[],t.resolve=t,t.id=28130,e.exports=t},27072:(e,t,i)=>{var s=i(92604);e.exports=s},14598:(e,t,i)=>{var s=i(73837),r=i(12781).Stream,n=i(65239);function o(){this.writable=!1,this.readable=!0,this.dataSize=0,this.maxDataSize=2097152,this.pauseStreams=!0,this._released=!1,this._streams=[],this._currentStream=null,this._insideLoop=!1,this._pendingNext=!1}e.exports=o,s.inherits(o,r),o.create=function(e){var t=new this;for(var i in e=e||{})t[i]=e[i];return t},o.isStreamLike=function(e){return"function"!=typeof e&&"string"!=typeof e&&"boolean"!=typeof e&&"number"!=typeof e&&!Buffer.isBuffer(e)},o.prototype.append=function(e){if(o.isStreamLike(e)){if(!(e instanceof n)){var t=n.create(e,{maxDataSize:1/0,pauseStream:this.pauseStreams});e.on("data",this._checkDataSize.bind(this)),e=t}this._handleErrors(e),this.pauseStreams&&e.pause()}return this._streams.push(e),this},o.prototype.pipe=function(e,t){return r.prototype.pipe.call(this,e,t),this.resume(),e},o.prototype._getNext=function(){if(this._currentStream=null,this._insideLoop)this._pendingNext=!0;else{this._insideLoop=!0;try{do{this._pendingNext=!1,this._realGetNext()}while(this._pendingNext)}finally{this._insideLoop=!1}}},o.prototype._realGetNext=function(){var e=this._streams.shift();void 0!==e?"function"==typeof e?e(function(e){o.isStreamLike(e)&&(e.on("data",this._checkDataSize.bind(this)),this._handleErrors(e)),this._pipeNext(e)}.bind(this)):this._pipeNext(e):this.end()},o.prototype._pipeNext=function(e){if(this._currentStream=e,o.isStreamLike(e))return e.on("end",this._getNext.bind(this)),void e.pipe(this,{end:!1});var t=e;this.write(t),this._getNext()},o.prototype._handleErrors=function(e){var t=this;e.on("error",(function(e){t._emitError(e)}))},o.prototype.write=function(e){this.emit("data",e)},o.prototype.pause=function(){this.pauseStreams&&(this.pauseStreams&&this._currentStream&&"function"==typeof this._currentStream.pause&&this._currentStream.pause(),this.emit("pause"))},o.prototype.resume=function(){this._released||(this._released=!0,this.writable=!0,this._getNext()),this.pauseStreams&&this._currentStream&&"function"==typeof this._currentStream.resume&&this._currentStream.resume(),this.emit("resume")},o.prototype.end=function(){this._reset(),this.emit("end")},o.prototype.destroy=function(){this._reset(),this.emit("close")},o.prototype._reset=function(){this.writable=!1,this._streams=[],this._currentStream=null},o.prototype._checkDataSize=function(){if(this._updateDataSize(),!(this.dataSize<=this.maxDataSize)){var e="DelayedStream#maxDataSize of "+this.maxDataSize+" bytes exceeded.";this._emitError(new Error(e))}},o.prototype._updateDataSize=function(){this.dataSize=0;var e=this;this._streams.forEach((function(t){t.dataSize&&(e.dataSize+=t.dataSize)})),this._currentStream&&this._currentStream.dataSize&&(this.dataSize+=this._currentStream.dataSize)},o.prototype._emitError=function(e){this._reset(),this.emit("error",e)}},95146:(e,t,i)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const i="color: "+this.color;t.splice(1,0,i,"color: inherit");let s=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(s++,"%c"===e&&(r=s))})),t.splice(r,0,i)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=i(17498)(t);const{formatters:s}=e.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},17498:(e,t,i)=>{e.exports=function(e){function t(e){let i,r,n,o=null;function a(...e){if(!a.enabled)return;const s=a,r=Number(new Date),n=r-(i||r);s.diff=n,s.prev=i,s.curr=r,i=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let o=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((i,r)=>{if("%%"===i)return"%";o++;const n=t.formatters[r];if("function"==typeof n){const t=e[o];i=n.call(s,t),e.splice(o,1),o--}return i})),t.formatArgs.call(s,e),(s.log||t.log).apply(s,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=s,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==o?o:(r!==t.namespaces&&(r=t.namespaces,n=t.enabled(e)),n),set:e=>{o=e}}),"function"==typeof t.init&&t.init(a),a}function s(e,i){const s=t(this.namespace+(void 0===i?":":i)+e);return s.log=this.log,s}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let i;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const s=("string"==typeof e?e:"").split(/[\s,]+/),r=s.length;for(i=0;i{t[i]=e[i]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let i=0;for(let t=0;t{"undefined"==typeof process||"renderer"===process.type||!0===process.browser||process.__nwjs?e.exports=i(95146):e.exports=i(46072)},46072:(e,t,i)=>{const s=i(76224),r=i(73837);t.init=function(e){e.inspectOpts={};const i=Object.keys(t.inspectOpts);for(let s=0;s{}),"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."),t.colors=[6,2,3,4,5,1];try{const e=i(56778);e&&(e.stderr||e).level>=2&&(t.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch(e){}t.inspectOpts=Object.keys(process.env).filter((e=>/^debug_/i.test(e))).reduce(((e,t)=>{const i=t.substring(6).toLowerCase().replace(/_([a-z])/g,((e,t)=>t.toUpperCase()));let s=process.env[t];return s=!!/^(yes|on|true|enabled)$/i.test(s)||!/^(no|off|false|disabled)$/i.test(s)&&("null"===s?null:Number(s)),e[i]=s,e}),{}),e.exports=i(17498)(t);const{formatters:n}=e.exports;n.o=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts).split("\n").map((e=>e.trim())).join(" ")},n.O=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts)}},70596:(e,t,i)=>{var s=i(54256);e.exports=function(e,t){return e=e||{},Object.keys(t).forEach((function(i){void 0===e[i]&&(e[i]=s(t[i]))})),e}},65239:(e,t,i)=>{var s=i(12781).Stream,r=i(73837);function n(){this.source=null,this.dataSize=0,this.maxDataSize=1048576,this.pauseStream=!0,this._maxDataSizeExceeded=!1,this._released=!1,this._bufferedEvents=[]}e.exports=n,r.inherits(n,s),n.create=function(e,t){var i=new this;for(var s in t=t||{})i[s]=t[s];i.source=e;var r=e.emit;return e.emit=function(){return i._handleEmit(arguments),r.apply(e,arguments)},e.on("error",(function(){})),i.pauseStream&&e.pause(),i},Object.defineProperty(n.prototype,"readable",{configurable:!0,enumerable:!0,get:function(){return this.source.readable}}),n.prototype.setEncoding=function(){return this.source.setEncoding.apply(this.source,arguments)},n.prototype.resume=function(){this._released||this.release(),this.source.resume()},n.prototype.pause=function(){this.source.pause()},n.prototype.release=function(){this._released=!0,this._bufferedEvents.forEach(function(e){this.emit.apply(this,e)}.bind(this)),this._bufferedEvents=[]},n.prototype.pipe=function(){var e=s.prototype.pipe.apply(this,arguments);return this.resume(),e},n.prototype._handleEmit=function(e){this._released?this.emit.apply(this,e):("data"===e[0]&&(this.dataSize+=e[1].length,this._checkIfMaxDataSizeExceeded()),this._bufferedEvents.push(e))},n.prototype._checkIfMaxDataSizeExceeded=function(){if(!(this._maxDataSizeExceeded||this.dataSize<=this.maxDataSize)){this._maxDataSizeExceeded=!0;var e="DelayedStream#maxDataSize of "+this.maxDataSize+" bytes exceeded.";this.emit("error",new Error(e))}}},57751:(e,t,i)=>{"use strict";i.r(t),i.d(t,{Deprecation:()=>s});class s extends Error{constructor(e){super(e),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name="Deprecation"}}},90772:(e,t,i)=>{const s=i(57147),r=i(71017),n=i(22037);function o(e){console.log(`[dotenv][DEBUG] ${e}`)}const a=/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/,c=/\\n/g,l=/\r\n|\n|\r/;function p(e,t){const i=Boolean(t&&t.debug),s={};return e.toString().split(l).forEach((function(e,t){const r=e.match(a);if(null!=r){const e=r[1];let t=r[2]||"";const i=t.length-1,n='"'===t[0]&&'"'===t[i];"'"===t[0]&&"'"===t[i]||n?(t=t.substring(1,i),n&&(t=t.replace(c,"\n"))):t=t.trim(),s[e]=t}else i&&o(`did not match key and value when parsing line ${t+1}: ${e}`)})),s}e.exports.config=function(e){let t=r.resolve(process.cwd(),".env"),i="utf8",a=!1;var c;e&&(null!=e.path&&(t="~"===(c=e.path)[0]?r.join(n.homedir(),c.slice(1)):c),null!=e.encoding&&(i=e.encoding),null!=e.debug&&(a=!0));try{const e=p(s.readFileSync(t,{encoding:i}),{debug:a});return Object.keys(e).forEach((function(t){Object.prototype.hasOwnProperty.call(process.env,t)?a&&o(`"${t}" is already defined in \`process.env\` and will not be overwritten`):process.env[t]=e[t]})),{parsed:e}}catch(e){return{error:e}}},e.exports.parse=p},87491:function(e){var t;t=function(){return function(e){var t={};function i(s){if(t[s])return t[s].exports;var r=t[s]={exports:{},id:s,loaded:!1};return e[s].call(r.exports,r,r.exports,i),r.loaded=!0,r.exports}return i.m=e,i.c=t,i.p="",i(0)}([function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=i(1),r=i(3),n=i(8),o=i(15);function a(e,t,i){var o=null,a=function(e,t){i&&i(e,t),o&&o.visit(e,t)},c="function"==typeof i?a:null,l=!1;if(t){l="boolean"==typeof t.comment&&t.comment;var p="boolean"==typeof t.attachComment&&t.attachComment;(l||p)&&((o=new s.CommentHandler).attach=p,t.comment=!0,c=a)}var A,u=!1;t&&"string"==typeof t.sourceType&&(u="module"===t.sourceType),A=t&&"boolean"==typeof t.jsx&&t.jsx?new r.JSXParser(e,t,c):new n.Parser(e,t,c);var d=u?A.parseModule():A.parseScript();return l&&o&&(d.comments=o.comments),A.config.tokens&&(d.tokens=A.tokens),A.config.tolerant&&(d.errors=A.errorHandler.errors),d}t.parse=a,t.parseModule=function(e,t,i){var s=t||{};return s.sourceType="module",a(e,s,i)},t.parseScript=function(e,t,i){var s=t||{};return s.sourceType="script",a(e,s,i)},t.tokenize=function(e,t,i){var s,r=new o.Tokenizer(e,t);s=[];try{for(;;){var n=r.getNextToken();if(!n)break;i&&(n=i(n)),s.push(n)}}catch(e){r.errorHandler.tolerate(e)}return r.errorHandler.tolerant&&(s.errors=r.errors()),s};var c=i(2);t.Syntax=c.Syntax,t.version="4.0.1"},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=i(2),r=function(){function e(){this.attach=!1,this.comments=[],this.stack=[],this.leading=[],this.trailing=[]}return e.prototype.insertInnerComments=function(e,t){if(e.type===s.Syntax.BlockStatement&&0===e.body.length){for(var i=[],r=this.leading.length-1;r>=0;--r){var n=this.leading[r];t.end.offset>=n.start&&(i.unshift(n.comment),this.leading.splice(r,1),this.trailing.splice(r,1))}i.length&&(e.innerComments=i)}},e.prototype.findTrailingComments=function(e){var t=[];if(this.trailing.length>0){for(var i=this.trailing.length-1;i>=0;--i){var s=this.trailing[i];s.start>=e.end.offset&&t.unshift(s.comment)}return this.trailing.length=0,t}var r=this.stack[this.stack.length-1];if(r&&r.node.trailingComments){var n=r.node.trailingComments[0];n&&n.range[0]>=e.end.offset&&(t=r.node.trailingComments,delete r.node.trailingComments)}return t},e.prototype.findLeadingComments=function(e){for(var t,i=[];this.stack.length>0&&(n=this.stack[this.stack.length-1])&&n.start>=e.start.offset;)t=n.node,this.stack.pop();if(t){for(var s=(t.leadingComments?t.leadingComments.length:0)-1;s>=0;--s){var r=t.leadingComments[s];r.range[1]<=e.start.offset&&(i.unshift(r),t.leadingComments.splice(s,1))}return t.leadingComments&&0===t.leadingComments.length&&delete t.leadingComments,i}for(s=this.leading.length-1;s>=0;--s){var n;(n=this.leading[s]).start<=e.start.offset&&(i.unshift(n.comment),this.leading.splice(s,1))}return i},e.prototype.visitNode=function(e,t){if(!(e.type===s.Syntax.Program&&e.body.length>0)){this.insertInnerComments(e,t);var i=this.findTrailingComments(t),r=this.findLeadingComments(t);r.length>0&&(e.leadingComments=r),i.length>0&&(e.trailingComments=i),this.stack.push({node:e,start:t.start.offset})}},e.prototype.visitComment=function(e,t){var i="L"===e.type[0]?"Line":"Block",s={type:i,value:e.value};if(e.range&&(s.range=e.range),e.loc&&(s.loc=e.loc),this.comments.push(s),this.attach){var r={comment:{type:i,value:e.value,range:[t.start.offset,t.end.offset]},start:t.start.offset};e.loc&&(r.comment.loc=e.loc),e.type=i,this.leading.push(r),this.trailing.push(r)}},e.prototype.visit=function(e,t){"LineComment"===e.type||"BlockComment"===e.type?this.visitComment(e,t):this.attach&&this.visitNode(e,t)},e}();t.CommentHandler=r},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Syntax={AssignmentExpression:"AssignmentExpression",AssignmentPattern:"AssignmentPattern",ArrayExpression:"ArrayExpression",ArrayPattern:"ArrayPattern",ArrowFunctionExpression:"ArrowFunctionExpression",AwaitExpression:"AwaitExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ClassBody:"ClassBody",ClassDeclaration:"ClassDeclaration",ClassExpression:"ClassExpression",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExportAllDeclaration:"ExportAllDeclaration",ExportDefaultDeclaration:"ExportDefaultDeclaration",ExportNamedDeclaration:"ExportNamedDeclaration",ExportSpecifier:"ExportSpecifier",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForOfStatement:"ForOfStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",ImportDeclaration:"ImportDeclaration",ImportDefaultSpecifier:"ImportDefaultSpecifier",ImportNamespaceSpecifier:"ImportNamespaceSpecifier",ImportSpecifier:"ImportSpecifier",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",MetaProperty:"MetaProperty",MethodDefinition:"MethodDefinition",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",ObjectPattern:"ObjectPattern",Program:"Program",Property:"Property",RestElement:"RestElement",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SpreadElement:"SpreadElement",Super:"Super",SwitchCase:"SwitchCase",SwitchStatement:"SwitchStatement",TaggedTemplateExpression:"TaggedTemplateExpression",TemplateElement:"TemplateElement",TemplateLiteral:"TemplateLiteral",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement",YieldExpression:"YieldExpression"}},function(e,t,i){"use strict";var s,r=this&&this.__extends||(s=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var i in t)t.hasOwnProperty(i)&&(e[i]=t[i])},function(e,t){function i(){this.constructor=e}s(e,t),e.prototype=null===t?Object.create(t):(i.prototype=t.prototype,new i)});Object.defineProperty(t,"__esModule",{value:!0});var n=i(4),o=i(5),a=i(6),c=i(7),l=i(8),p=i(13),A=i(14);function u(e){var t;switch(e.type){case a.JSXSyntax.JSXIdentifier:t=e.name;break;case a.JSXSyntax.JSXNamespacedName:var i=e;t=u(i.namespace)+":"+u(i.name);break;case a.JSXSyntax.JSXMemberExpression:var s=e;t=u(s.object)+"."+u(s.property)}return t}p.TokenName[100]="JSXIdentifier",p.TokenName[101]="JSXText";var d=function(e){function t(t,i,s){return e.call(this,t,i,s)||this}return r(t,e),t.prototype.parsePrimaryExpression=function(){return this.match("<")?this.parseJSXRoot():e.prototype.parsePrimaryExpression.call(this)},t.prototype.startJSX=function(){this.scanner.index=this.startMarker.index,this.scanner.lineNumber=this.startMarker.line,this.scanner.lineStart=this.startMarker.index-this.startMarker.column},t.prototype.finishJSX=function(){this.nextToken()},t.prototype.reenterJSX=function(){this.startJSX(),this.expectJSX("}"),this.config.tokens&&this.tokens.pop()},t.prototype.createJSXNode=function(){return this.collectComments(),{index:this.scanner.index,line:this.scanner.lineNumber,column:this.scanner.index-this.scanner.lineStart}},t.prototype.createJSXChildNode=function(){return{index:this.scanner.index,line:this.scanner.lineNumber,column:this.scanner.index-this.scanner.lineStart}},t.prototype.scanXHTMLEntity=function(e){for(var t="&",i=!0,s=!1,r=!1,o=!1;!this.scanner.eof()&&i&&!s;){var a=this.scanner.source[this.scanner.index];if(a===e)break;if(s=";"===a,t+=a,++this.scanner.index,!s)switch(t.length){case 2:r="#"===a;break;case 3:r&&(i=(o="x"===a)||n.Character.isDecimalDigit(a.charCodeAt(0)),r=r&&!o);break;default:i=(i=i&&!(r&&!n.Character.isDecimalDigit(a.charCodeAt(0))))&&!(o&&!n.Character.isHexDigit(a.charCodeAt(0)))}}if(i&&s&&t.length>2){var c=t.substr(1,t.length-2);r&&c.length>1?t=String.fromCharCode(parseInt(c.substr(1),10)):o&&c.length>2?t=String.fromCharCode(parseInt("0"+c.substr(1),16)):r||o||!A.XHTMLEntities[c]||(t=A.XHTMLEntities[c])}return t},t.prototype.lexJSX=function(){var e=this.scanner.source.charCodeAt(this.scanner.index);if(60===e||62===e||47===e||58===e||61===e||123===e||125===e)return{type:7,value:a=this.scanner.source[this.scanner.index++],lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:this.scanner.index-1,end:this.scanner.index};if(34===e||39===e){for(var t=this.scanner.index,i=this.scanner.source[this.scanner.index++],s="";!this.scanner.eof()&&(c=this.scanner.source[this.scanner.index++])!==i;)s+="&"===c?this.scanXHTMLEntity(i):c;return{type:8,value:s,lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:t,end:this.scanner.index}}if(46===e){var r=this.scanner.source.charCodeAt(this.scanner.index+1),o=this.scanner.source.charCodeAt(this.scanner.index+2),a=46===r&&46===o?"...":".";return t=this.scanner.index,this.scanner.index+=a.length,{type:7,value:a,lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:t,end:this.scanner.index}}if(96===e)return{type:10,value:"",lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:this.scanner.index,end:this.scanner.index};if(n.Character.isIdentifierStart(e)&&92!==e){for(t=this.scanner.index,++this.scanner.index;!this.scanner.eof();){var c=this.scanner.source.charCodeAt(this.scanner.index);if(n.Character.isIdentifierPart(c)&&92!==c)++this.scanner.index;else{if(45!==c)break;++this.scanner.index}}return{type:100,value:this.scanner.source.slice(t,this.scanner.index),lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:t,end:this.scanner.index}}return this.scanner.lex()},t.prototype.nextJSXToken=function(){this.collectComments(),this.startMarker.index=this.scanner.index,this.startMarker.line=this.scanner.lineNumber,this.startMarker.column=this.scanner.index-this.scanner.lineStart;var e=this.lexJSX();return this.lastMarker.index=this.scanner.index,this.lastMarker.line=this.scanner.lineNumber,this.lastMarker.column=this.scanner.index-this.scanner.lineStart,this.config.tokens&&this.tokens.push(this.convertToken(e)),e},t.prototype.nextJSXText=function(){this.startMarker.index=this.scanner.index,this.startMarker.line=this.scanner.lineNumber,this.startMarker.column=this.scanner.index-this.scanner.lineStart;for(var e=this.scanner.index,t="";!this.scanner.eof();){var i=this.scanner.source[this.scanner.index];if("{"===i||"<"===i)break;++this.scanner.index,t+=i,n.Character.isLineTerminator(i.charCodeAt(0))&&(++this.scanner.lineNumber,"\r"===i&&"\n"===this.scanner.source[this.scanner.index]&&++this.scanner.index,this.scanner.lineStart=this.scanner.index)}this.lastMarker.index=this.scanner.index,this.lastMarker.line=this.scanner.lineNumber,this.lastMarker.column=this.scanner.index-this.scanner.lineStart;var s={type:101,value:t,lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:e,end:this.scanner.index};return t.length>0&&this.config.tokens&&this.tokens.push(this.convertToken(s)),s},t.prototype.peekJSXToken=function(){var e=this.scanner.saveState();this.scanner.scanComments();var t=this.lexJSX();return this.scanner.restoreState(e),t},t.prototype.expectJSX=function(e){var t=this.nextJSXToken();7===t.type&&t.value===e||this.throwUnexpectedToken(t)},t.prototype.matchJSX=function(e){var t=this.peekJSXToken();return 7===t.type&&t.value===e},t.prototype.parseJSXIdentifier=function(){var e=this.createJSXNode(),t=this.nextJSXToken();return 100!==t.type&&this.throwUnexpectedToken(t),this.finalize(e,new o.JSXIdentifier(t.value))},t.prototype.parseJSXElementName=function(){var e=this.createJSXNode(),t=this.parseJSXIdentifier();if(this.matchJSX(":")){var i=t;this.expectJSX(":");var s=this.parseJSXIdentifier();t=this.finalize(e,new o.JSXNamespacedName(i,s))}else if(this.matchJSX("."))for(;this.matchJSX(".");){var r=t;this.expectJSX(".");var n=this.parseJSXIdentifier();t=this.finalize(e,new o.JSXMemberExpression(r,n))}return t},t.prototype.parseJSXAttributeName=function(){var e,t=this.createJSXNode(),i=this.parseJSXIdentifier();if(this.matchJSX(":")){var s=i;this.expectJSX(":");var r=this.parseJSXIdentifier();e=this.finalize(t,new o.JSXNamespacedName(s,r))}else e=i;return e},t.prototype.parseJSXStringLiteralAttribute=function(){var e=this.createJSXNode(),t=this.nextJSXToken();8!==t.type&&this.throwUnexpectedToken(t);var i=this.getTokenRaw(t);return this.finalize(e,new c.Literal(t.value,i))},t.prototype.parseJSXExpressionAttribute=function(){var e=this.createJSXNode();this.expectJSX("{"),this.finishJSX(),this.match("}")&&this.tolerateError("JSX attributes must only be assigned a non-empty expression");var t=this.parseAssignmentExpression();return this.reenterJSX(),this.finalize(e,new o.JSXExpressionContainer(t))},t.prototype.parseJSXAttributeValue=function(){return this.matchJSX("{")?this.parseJSXExpressionAttribute():this.matchJSX("<")?this.parseJSXElement():this.parseJSXStringLiteralAttribute()},t.prototype.parseJSXNameValueAttribute=function(){var e=this.createJSXNode(),t=this.parseJSXAttributeName(),i=null;return this.matchJSX("=")&&(this.expectJSX("="),i=this.parseJSXAttributeValue()),this.finalize(e,new o.JSXAttribute(t,i))},t.prototype.parseJSXSpreadAttribute=function(){var e=this.createJSXNode();this.expectJSX("{"),this.expectJSX("..."),this.finishJSX();var t=this.parseAssignmentExpression();return this.reenterJSX(),this.finalize(e,new o.JSXSpreadAttribute(t))},t.prototype.parseJSXAttributes=function(){for(var e=[];!this.matchJSX("/")&&!this.matchJSX(">");){var t=this.matchJSX("{")?this.parseJSXSpreadAttribute():this.parseJSXNameValueAttribute();e.push(t)}return e},t.prototype.parseJSXOpeningElement=function(){var e=this.createJSXNode();this.expectJSX("<");var t=this.parseJSXElementName(),i=this.parseJSXAttributes(),s=this.matchJSX("/");return s&&this.expectJSX("/"),this.expectJSX(">"),this.finalize(e,new o.JSXOpeningElement(t,s,i))},t.prototype.parseJSXBoundaryElement=function(){var e=this.createJSXNode();if(this.expectJSX("<"),this.matchJSX("/")){this.expectJSX("/");var t=this.parseJSXElementName();return this.expectJSX(">"),this.finalize(e,new o.JSXClosingElement(t))}var i=this.parseJSXElementName(),s=this.parseJSXAttributes(),r=this.matchJSX("/");return r&&this.expectJSX("/"),this.expectJSX(">"),this.finalize(e,new o.JSXOpeningElement(i,r,s))},t.prototype.parseJSXEmptyExpression=function(){var e=this.createJSXChildNode();return this.collectComments(),this.lastMarker.index=this.scanner.index,this.lastMarker.line=this.scanner.lineNumber,this.lastMarker.column=this.scanner.index-this.scanner.lineStart,this.finalize(e,new o.JSXEmptyExpression)},t.prototype.parseJSXExpressionContainer=function(){var e,t=this.createJSXNode();return this.expectJSX("{"),this.matchJSX("}")?(e=this.parseJSXEmptyExpression(),this.expectJSX("}")):(this.finishJSX(),e=this.parseAssignmentExpression(),this.reenterJSX()),this.finalize(t,new o.JSXExpressionContainer(e))},t.prototype.parseJSXChildren=function(){for(var e=[];!this.scanner.eof();){var t=this.createJSXChildNode(),i=this.nextJSXText();if(i.start0))break;n=this.finalize(e.node,new o.JSXElement(e.opening,e.children,e.closing)),(e=t[t.length-1]).children.push(n),t.pop()}}return e},t.prototype.parseJSXElement=function(){var e=this.createJSXNode(),t=this.parseJSXOpeningElement(),i=[],s=null;if(!t.selfClosing){var r=this.parseComplexJSXElement({node:e,opening:t,closing:s,children:i});i=r.children,s=r.closing}return this.finalize(e,new o.JSXElement(t,i,s))},t.prototype.parseJSXRoot=function(){this.config.tokens&&this.tokens.pop(),this.startJSX();var e=this.parseJSXElement();return this.finishJSX(),e},t.prototype.isStartOfExpression=function(){return e.prototype.isStartOfExpression.call(this)||this.match("<")},t}(l.Parser);t.JSXParser=d},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i={NonAsciiIdentifierStart:/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/,NonAsciiIdentifierPart:/[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/};t.Character={fromCodePoint:function(e){return e<65536?String.fromCharCode(e):String.fromCharCode(55296+(e-65536>>10))+String.fromCharCode(56320+(e-65536&1023))},isWhiteSpace:function(e){return 32===e||9===e||11===e||12===e||160===e||e>=5760&&[5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(e)>=0},isLineTerminator:function(e){return 10===e||13===e||8232===e||8233===e},isIdentifierStart:function(e){return 36===e||95===e||e>=65&&e<=90||e>=97&&e<=122||92===e||e>=128&&i.NonAsciiIdentifierStart.test(t.Character.fromCodePoint(e))},isIdentifierPart:function(e){return 36===e||95===e||e>=65&&e<=90||e>=97&&e<=122||e>=48&&e<=57||92===e||e>=128&&i.NonAsciiIdentifierPart.test(t.Character.fromCodePoint(e))},isDecimalDigit:function(e){return e>=48&&e<=57},isHexDigit:function(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102},isOctalDigit:function(e){return e>=48&&e<=55}}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=i(6);t.JSXClosingElement=function(e){this.type=s.JSXSyntax.JSXClosingElement,this.name=e};t.JSXElement=function(e,t,i){this.type=s.JSXSyntax.JSXElement,this.openingElement=e,this.children=t,this.closingElement=i};t.JSXEmptyExpression=function(){this.type=s.JSXSyntax.JSXEmptyExpression};t.JSXExpressionContainer=function(e){this.type=s.JSXSyntax.JSXExpressionContainer,this.expression=e};t.JSXIdentifier=function(e){this.type=s.JSXSyntax.JSXIdentifier,this.name=e};t.JSXMemberExpression=function(e,t){this.type=s.JSXSyntax.JSXMemberExpression,this.object=e,this.property=t};t.JSXAttribute=function(e,t){this.type=s.JSXSyntax.JSXAttribute,this.name=e,this.value=t};t.JSXNamespacedName=function(e,t){this.type=s.JSXSyntax.JSXNamespacedName,this.namespace=e,this.name=t};t.JSXOpeningElement=function(e,t,i){this.type=s.JSXSyntax.JSXOpeningElement,this.name=e,this.selfClosing=t,this.attributes=i};t.JSXSpreadAttribute=function(e){this.type=s.JSXSyntax.JSXSpreadAttribute,this.argument=e};t.JSXText=function(e,t){this.type=s.JSXSyntax.JSXText,this.value=e,this.raw=t}},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.JSXSyntax={JSXAttribute:"JSXAttribute",JSXClosingElement:"JSXClosingElement",JSXElement:"JSXElement",JSXEmptyExpression:"JSXEmptyExpression",JSXExpressionContainer:"JSXExpressionContainer",JSXIdentifier:"JSXIdentifier",JSXMemberExpression:"JSXMemberExpression",JSXNamespacedName:"JSXNamespacedName",JSXOpeningElement:"JSXOpeningElement",JSXSpreadAttribute:"JSXSpreadAttribute",JSXText:"JSXText"}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=i(2);t.ArrayExpression=function(e){this.type=s.Syntax.ArrayExpression,this.elements=e};t.ArrayPattern=function(e){this.type=s.Syntax.ArrayPattern,this.elements=e};t.ArrowFunctionExpression=function(e,t,i){this.type=s.Syntax.ArrowFunctionExpression,this.id=null,this.params=e,this.body=t,this.generator=!1,this.expression=i,this.async=!1};t.AssignmentExpression=function(e,t,i){this.type=s.Syntax.AssignmentExpression,this.operator=e,this.left=t,this.right=i};t.AssignmentPattern=function(e,t){this.type=s.Syntax.AssignmentPattern,this.left=e,this.right=t};t.AsyncArrowFunctionExpression=function(e,t,i){this.type=s.Syntax.ArrowFunctionExpression,this.id=null,this.params=e,this.body=t,this.generator=!1,this.expression=i,this.async=!0};t.AsyncFunctionDeclaration=function(e,t,i){this.type=s.Syntax.FunctionDeclaration,this.id=e,this.params=t,this.body=i,this.generator=!1,this.expression=!1,this.async=!0};t.AsyncFunctionExpression=function(e,t,i){this.type=s.Syntax.FunctionExpression,this.id=e,this.params=t,this.body=i,this.generator=!1,this.expression=!1,this.async=!0};t.AwaitExpression=function(e){this.type=s.Syntax.AwaitExpression,this.argument=e};t.BinaryExpression=function(e,t,i){var r="||"===e||"&&"===e;this.type=r?s.Syntax.LogicalExpression:s.Syntax.BinaryExpression,this.operator=e,this.left=t,this.right=i};t.BlockStatement=function(e){this.type=s.Syntax.BlockStatement,this.body=e};t.BreakStatement=function(e){this.type=s.Syntax.BreakStatement,this.label=e};t.CallExpression=function(e,t){this.type=s.Syntax.CallExpression,this.callee=e,this.arguments=t};t.CatchClause=function(e,t){this.type=s.Syntax.CatchClause,this.param=e,this.body=t};t.ClassBody=function(e){this.type=s.Syntax.ClassBody,this.body=e};t.ClassDeclaration=function(e,t,i){this.type=s.Syntax.ClassDeclaration,this.id=e,this.superClass=t,this.body=i};t.ClassExpression=function(e,t,i){this.type=s.Syntax.ClassExpression,this.id=e,this.superClass=t,this.body=i};t.ComputedMemberExpression=function(e,t){this.type=s.Syntax.MemberExpression,this.computed=!0,this.object=e,this.property=t};t.ConditionalExpression=function(e,t,i){this.type=s.Syntax.ConditionalExpression,this.test=e,this.consequent=t,this.alternate=i};t.ContinueStatement=function(e){this.type=s.Syntax.ContinueStatement,this.label=e};t.DebuggerStatement=function(){this.type=s.Syntax.DebuggerStatement};t.Directive=function(e,t){this.type=s.Syntax.ExpressionStatement,this.expression=e,this.directive=t};t.DoWhileStatement=function(e,t){this.type=s.Syntax.DoWhileStatement,this.body=e,this.test=t};t.EmptyStatement=function(){this.type=s.Syntax.EmptyStatement};t.ExportAllDeclaration=function(e){this.type=s.Syntax.ExportAllDeclaration,this.source=e};t.ExportDefaultDeclaration=function(e){this.type=s.Syntax.ExportDefaultDeclaration,this.declaration=e};t.ExportNamedDeclaration=function(e,t,i){this.type=s.Syntax.ExportNamedDeclaration,this.declaration=e,this.specifiers=t,this.source=i};t.ExportSpecifier=function(e,t){this.type=s.Syntax.ExportSpecifier,this.exported=t,this.local=e};t.ExpressionStatement=function(e){this.type=s.Syntax.ExpressionStatement,this.expression=e};t.ForInStatement=function(e,t,i){this.type=s.Syntax.ForInStatement,this.left=e,this.right=t,this.body=i,this.each=!1};t.ForOfStatement=function(e,t,i){this.type=s.Syntax.ForOfStatement,this.left=e,this.right=t,this.body=i};t.ForStatement=function(e,t,i,r){this.type=s.Syntax.ForStatement,this.init=e,this.test=t,this.update=i,this.body=r};t.FunctionDeclaration=function(e,t,i,r){this.type=s.Syntax.FunctionDeclaration,this.id=e,this.params=t,this.body=i,this.generator=r,this.expression=!1,this.async=!1};t.FunctionExpression=function(e,t,i,r){this.type=s.Syntax.FunctionExpression,this.id=e,this.params=t,this.body=i,this.generator=r,this.expression=!1,this.async=!1};t.Identifier=function(e){this.type=s.Syntax.Identifier,this.name=e};t.IfStatement=function(e,t,i){this.type=s.Syntax.IfStatement,this.test=e,this.consequent=t,this.alternate=i};t.ImportDeclaration=function(e,t){this.type=s.Syntax.ImportDeclaration,this.specifiers=e,this.source=t};t.ImportDefaultSpecifier=function(e){this.type=s.Syntax.ImportDefaultSpecifier,this.local=e};t.ImportNamespaceSpecifier=function(e){this.type=s.Syntax.ImportNamespaceSpecifier,this.local=e};t.ImportSpecifier=function(e,t){this.type=s.Syntax.ImportSpecifier,this.local=e,this.imported=t};t.LabeledStatement=function(e,t){this.type=s.Syntax.LabeledStatement,this.label=e,this.body=t};t.Literal=function(e,t){this.type=s.Syntax.Literal,this.value=e,this.raw=t};t.MetaProperty=function(e,t){this.type=s.Syntax.MetaProperty,this.meta=e,this.property=t};t.MethodDefinition=function(e,t,i,r,n){this.type=s.Syntax.MethodDefinition,this.key=e,this.computed=t,this.value=i,this.kind=r,this.static=n};t.Module=function(e){this.type=s.Syntax.Program,this.body=e,this.sourceType="module"};t.NewExpression=function(e,t){this.type=s.Syntax.NewExpression,this.callee=e,this.arguments=t};t.ObjectExpression=function(e){this.type=s.Syntax.ObjectExpression,this.properties=e};t.ObjectPattern=function(e){this.type=s.Syntax.ObjectPattern,this.properties=e};t.Property=function(e,t,i,r,n,o){this.type=s.Syntax.Property,this.key=t,this.computed=i,this.value=r,this.kind=e,this.method=n,this.shorthand=o};t.RegexLiteral=function(e,t,i,r){this.type=s.Syntax.Literal,this.value=e,this.raw=t,this.regex={pattern:i,flags:r}};t.RestElement=function(e){this.type=s.Syntax.RestElement,this.argument=e};t.ReturnStatement=function(e){this.type=s.Syntax.ReturnStatement,this.argument=e};t.Script=function(e){this.type=s.Syntax.Program,this.body=e,this.sourceType="script"};t.SequenceExpression=function(e){this.type=s.Syntax.SequenceExpression,this.expressions=e};t.SpreadElement=function(e){this.type=s.Syntax.SpreadElement,this.argument=e};t.StaticMemberExpression=function(e,t){this.type=s.Syntax.MemberExpression,this.computed=!1,this.object=e,this.property=t};t.Super=function(){this.type=s.Syntax.Super};t.SwitchCase=function(e,t){this.type=s.Syntax.SwitchCase,this.test=e,this.consequent=t};t.SwitchStatement=function(e,t){this.type=s.Syntax.SwitchStatement,this.discriminant=e,this.cases=t};t.TaggedTemplateExpression=function(e,t){this.type=s.Syntax.TaggedTemplateExpression,this.tag=e,this.quasi=t};t.TemplateElement=function(e,t){this.type=s.Syntax.TemplateElement,this.value=e,this.tail=t};t.TemplateLiteral=function(e,t){this.type=s.Syntax.TemplateLiteral,this.quasis=e,this.expressions=t};t.ThisExpression=function(){this.type=s.Syntax.ThisExpression};t.ThrowStatement=function(e){this.type=s.Syntax.ThrowStatement,this.argument=e};t.TryStatement=function(e,t,i){this.type=s.Syntax.TryStatement,this.block=e,this.handler=t,this.finalizer=i};t.UnaryExpression=function(e,t){this.type=s.Syntax.UnaryExpression,this.operator=e,this.argument=t,this.prefix=!0};t.UpdateExpression=function(e,t,i){this.type=s.Syntax.UpdateExpression,this.operator=e,this.argument=t,this.prefix=i};t.VariableDeclaration=function(e,t){this.type=s.Syntax.VariableDeclaration,this.declarations=e,this.kind=t};t.VariableDeclarator=function(e,t){this.type=s.Syntax.VariableDeclarator,this.id=e,this.init=t};t.WhileStatement=function(e,t){this.type=s.Syntax.WhileStatement,this.test=e,this.body=t};t.WithStatement=function(e,t){this.type=s.Syntax.WithStatement,this.object=e,this.body=t};t.YieldExpression=function(e,t){this.type=s.Syntax.YieldExpression,this.argument=e,this.delegate=t}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=i(9),r=i(10),n=i(11),o=i(7),a=i(12),c=i(2),l=i(13),p="ArrowParameterPlaceHolder",A=function(){function e(e,t,i){void 0===t&&(t={}),this.config={range:"boolean"==typeof t.range&&t.range,loc:"boolean"==typeof t.loc&&t.loc,source:null,tokens:"boolean"==typeof t.tokens&&t.tokens,comment:"boolean"==typeof t.comment&&t.comment,tolerant:"boolean"==typeof t.tolerant&&t.tolerant},this.config.loc&&t.source&&null!==t.source&&(this.config.source=String(t.source)),this.delegate=i,this.errorHandler=new r.ErrorHandler,this.errorHandler.tolerant=this.config.tolerant,this.scanner=new a.Scanner(e,this.errorHandler),this.scanner.trackComment=this.config.comment,this.operatorPrecedence={")":0,";":0,",":0,"=":0,"]":0,"||":1,"&&":2,"|":3,"^":4,"&":5,"==":6,"!=":6,"===":6,"!==":6,"<":7,">":7,"<=":7,">=":7,"<<":8,">>":8,">>>":8,"+":9,"-":9,"*":11,"/":11,"%":11},this.lookahead={type:2,value:"",lineNumber:this.scanner.lineNumber,lineStart:0,start:0,end:0},this.hasLineTerminator=!1,this.context={isModule:!1,await:!1,allowIn:!0,allowStrictDirective:!0,allowYield:!0,firstCoverInitializedNameError:null,isAssignmentTarget:!1,isBindingElement:!1,inFunctionBody:!1,inIteration:!1,inSwitch:!1,labelSet:{},strict:!1},this.tokens=[],this.startMarker={index:0,line:this.scanner.lineNumber,column:0},this.lastMarker={index:0,line:this.scanner.lineNumber,column:0},this.nextToken(),this.lastMarker={index:this.scanner.index,line:this.scanner.lineNumber,column:this.scanner.index-this.scanner.lineStart}}return e.prototype.throwError=function(e){for(var t=[],i=1;i0&&this.delegate)for(var t=0;t>="===e||">>>="===e||"&="===e||"^="===e||"|="===e},e.prototype.isolateCoverGrammar=function(e){var t=this.context.isBindingElement,i=this.context.isAssignmentTarget,s=this.context.firstCoverInitializedNameError;this.context.isBindingElement=!0,this.context.isAssignmentTarget=!0,this.context.firstCoverInitializedNameError=null;var r=e.call(this);return null!==this.context.firstCoverInitializedNameError&&this.throwUnexpectedToken(this.context.firstCoverInitializedNameError),this.context.isBindingElement=t,this.context.isAssignmentTarget=i,this.context.firstCoverInitializedNameError=s,r},e.prototype.inheritCoverGrammar=function(e){var t=this.context.isBindingElement,i=this.context.isAssignmentTarget,s=this.context.firstCoverInitializedNameError;this.context.isBindingElement=!0,this.context.isAssignmentTarget=!0,this.context.firstCoverInitializedNameError=null;var r=e.call(this);return this.context.isBindingElement=this.context.isBindingElement&&t,this.context.isAssignmentTarget=this.context.isAssignmentTarget&&i,this.context.firstCoverInitializedNameError=s||this.context.firstCoverInitializedNameError,r},e.prototype.consumeSemicolon=function(){this.match(";")?this.nextToken():this.hasLineTerminator||(2===this.lookahead.type||this.match("}")||this.throwUnexpectedToken(this.lookahead),this.lastMarker.index=this.startMarker.index,this.lastMarker.line=this.startMarker.line,this.lastMarker.column=this.startMarker.column)},e.prototype.parsePrimaryExpression=function(){var e,t,i,s=this.createNode();switch(this.lookahead.type){case 3:(this.context.isModule||this.context.await)&&"await"===this.lookahead.value&&this.tolerateUnexpectedToken(this.lookahead),e=this.matchAsyncFunction()?this.parseFunctionExpression():this.finalize(s,new o.Identifier(this.nextToken().value));break;case 6:case 8:this.context.strict&&this.lookahead.octal&&this.tolerateUnexpectedToken(this.lookahead,n.Messages.StrictOctalLiteral),this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,t=this.nextToken(),i=this.getTokenRaw(t),e=this.finalize(s,new o.Literal(t.value,i));break;case 1:this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,t=this.nextToken(),i=this.getTokenRaw(t),e=this.finalize(s,new o.Literal("true"===t.value,i));break;case 5:this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,t=this.nextToken(),i=this.getTokenRaw(t),e=this.finalize(s,new o.Literal(null,i));break;case 10:e=this.parseTemplateLiteral();break;case 7:switch(this.lookahead.value){case"(":this.context.isBindingElement=!1,e=this.inheritCoverGrammar(this.parseGroupExpression);break;case"[":e=this.inheritCoverGrammar(this.parseArrayInitializer);break;case"{":e=this.inheritCoverGrammar(this.parseObjectInitializer);break;case"/":case"/=":this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,this.scanner.index=this.startMarker.index,t=this.nextRegexToken(),i=this.getTokenRaw(t),e=this.finalize(s,new o.RegexLiteral(t.regex,i,t.pattern,t.flags));break;default:e=this.throwUnexpectedToken(this.nextToken())}break;case 4:!this.context.strict&&this.context.allowYield&&this.matchKeyword("yield")?e=this.parseIdentifierName():!this.context.strict&&this.matchKeyword("let")?e=this.finalize(s,new o.Identifier(this.nextToken().value)):(this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,this.matchKeyword("function")?e=this.parseFunctionExpression():this.matchKeyword("this")?(this.nextToken(),e=this.finalize(s,new o.ThisExpression)):e=this.matchKeyword("class")?this.parseClassExpression():this.throwUnexpectedToken(this.nextToken()));break;default:e=this.throwUnexpectedToken(this.nextToken())}return e},e.prototype.parseSpreadElement=function(){var e=this.createNode();this.expect("...");var t=this.inheritCoverGrammar(this.parseAssignmentExpression);return this.finalize(e,new o.SpreadElement(t))},e.prototype.parseArrayInitializer=function(){var e=this.createNode(),t=[];for(this.expect("[");!this.match("]");)if(this.match(","))this.nextToken(),t.push(null);else if(this.match("...")){var i=this.parseSpreadElement();this.match("]")||(this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,this.expect(",")),t.push(i)}else t.push(this.inheritCoverGrammar(this.parseAssignmentExpression)),this.match("]")||this.expect(",");return this.expect("]"),this.finalize(e,new o.ArrayExpression(t))},e.prototype.parsePropertyMethod=function(e){this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1;var t=this.context.strict,i=this.context.allowStrictDirective;this.context.allowStrictDirective=e.simple;var s=this.isolateCoverGrammar(this.parseFunctionSourceElements);return this.context.strict&&e.firstRestricted&&this.tolerateUnexpectedToken(e.firstRestricted,e.message),this.context.strict&&e.stricted&&this.tolerateUnexpectedToken(e.stricted,e.message),this.context.strict=t,this.context.allowStrictDirective=i,s},e.prototype.parsePropertyMethodFunction=function(){var e=this.createNode(),t=this.context.allowYield;this.context.allowYield=!0;var i=this.parseFormalParameters(),s=this.parsePropertyMethod(i);return this.context.allowYield=t,this.finalize(e,new o.FunctionExpression(null,i.params,s,!1))},e.prototype.parsePropertyMethodAsyncFunction=function(){var e=this.createNode(),t=this.context.allowYield,i=this.context.await;this.context.allowYield=!1,this.context.await=!0;var s=this.parseFormalParameters(),r=this.parsePropertyMethod(s);return this.context.allowYield=t,this.context.await=i,this.finalize(e,new o.AsyncFunctionExpression(null,s.params,r))},e.prototype.parseObjectPropertyKey=function(){var e,t=this.createNode(),i=this.nextToken();switch(i.type){case 8:case 6:this.context.strict&&i.octal&&this.tolerateUnexpectedToken(i,n.Messages.StrictOctalLiteral);var s=this.getTokenRaw(i);e=this.finalize(t,new o.Literal(i.value,s));break;case 3:case 1:case 5:case 4:e=this.finalize(t,new o.Identifier(i.value));break;case 7:"["===i.value?(e=this.isolateCoverGrammar(this.parseAssignmentExpression),this.expect("]")):e=this.throwUnexpectedToken(i);break;default:e=this.throwUnexpectedToken(i)}return e},e.prototype.isPropertyKey=function(e,t){return e.type===c.Syntax.Identifier&&e.name===t||e.type===c.Syntax.Literal&&e.value===t},e.prototype.parseObjectProperty=function(e){var t,i=this.createNode(),s=this.lookahead,r=null,a=null,c=!1,l=!1,p=!1,A=!1;if(3===s.type){var u=s.value;this.nextToken(),c=this.match("["),r=(A=!(this.hasLineTerminator||"async"!==u||this.match(":")||this.match("(")||this.match("*")||this.match(",")))?this.parseObjectPropertyKey():this.finalize(i,new o.Identifier(u))}else this.match("*")?this.nextToken():(c=this.match("["),r=this.parseObjectPropertyKey());var d=this.qualifiedPropertyName(this.lookahead);if(3===s.type&&!A&&"get"===s.value&&d)t="get",c=this.match("["),r=this.parseObjectPropertyKey(),this.context.allowYield=!1,a=this.parseGetterMethod();else if(3===s.type&&!A&&"set"===s.value&&d)t="set",c=this.match("["),r=this.parseObjectPropertyKey(),a=this.parseSetterMethod();else if(7===s.type&&"*"===s.value&&d)t="init",c=this.match("["),r=this.parseObjectPropertyKey(),a=this.parseGeneratorMethod(),l=!0;else if(r||this.throwUnexpectedToken(this.lookahead),t="init",this.match(":")&&!A)!c&&this.isPropertyKey(r,"__proto__")&&(e.value&&this.tolerateError(n.Messages.DuplicateProtoProperty),e.value=!0),this.nextToken(),a=this.inheritCoverGrammar(this.parseAssignmentExpression);else if(this.match("("))a=A?this.parsePropertyMethodAsyncFunction():this.parsePropertyMethodFunction(),l=!0;else if(3===s.type)if(u=this.finalize(i,new o.Identifier(s.value)),this.match("=")){this.context.firstCoverInitializedNameError=this.lookahead,this.nextToken(),p=!0;var h=this.isolateCoverGrammar(this.parseAssignmentExpression);a=this.finalize(i,new o.AssignmentPattern(u,h))}else p=!0,a=u;else this.throwUnexpectedToken(this.nextToken());return this.finalize(i,new o.Property(t,r,c,a,l,p))},e.prototype.parseObjectInitializer=function(){var e=this.createNode();this.expect("{");for(var t=[],i={value:!1};!this.match("}");)t.push(this.parseObjectProperty(i)),this.match("}")||this.expectCommaSeparator();return this.expect("}"),this.finalize(e,new o.ObjectExpression(t))},e.prototype.parseTemplateHead=function(){s.assert(this.lookahead.head,"Template literal must start with a template head");var e=this.createNode(),t=this.nextToken(),i=t.value,r=t.cooked;return this.finalize(e,new o.TemplateElement({raw:i,cooked:r},t.tail))},e.prototype.parseTemplateElement=function(){10!==this.lookahead.type&&this.throwUnexpectedToken();var e=this.createNode(),t=this.nextToken(),i=t.value,s=t.cooked;return this.finalize(e,new o.TemplateElement({raw:i,cooked:s},t.tail))},e.prototype.parseTemplateLiteral=function(){var e=this.createNode(),t=[],i=[],s=this.parseTemplateHead();for(i.push(s);!s.tail;)t.push(this.parseExpression()),s=this.parseTemplateElement(),i.push(s);return this.finalize(e,new o.TemplateLiteral(i,t))},e.prototype.reinterpretExpressionAsPattern=function(e){switch(e.type){case c.Syntax.Identifier:case c.Syntax.MemberExpression:case c.Syntax.RestElement:case c.Syntax.AssignmentPattern:break;case c.Syntax.SpreadElement:e.type=c.Syntax.RestElement,this.reinterpretExpressionAsPattern(e.argument);break;case c.Syntax.ArrayExpression:e.type=c.Syntax.ArrayPattern;for(var t=0;t")||this.expect("=>"),e={type:p,params:[],async:!1};else{var t=this.lookahead,i=[];if(this.match("..."))e=this.parseRestElement(i),this.expect(")"),this.match("=>")||this.expect("=>"),e={type:p,params:[e],async:!1};else{var s=!1;if(this.context.isBindingElement=!0,e=this.inheritCoverGrammar(this.parseAssignmentExpression),this.match(",")){var r=[];for(this.context.isAssignmentTarget=!1,r.push(e);2!==this.lookahead.type&&this.match(",");){if(this.nextToken(),this.match(")")){this.nextToken();for(var n=0;n")||this.expect("=>"),this.context.isBindingElement=!1,n=0;n")&&(e.type===c.Syntax.Identifier&&"yield"===e.name&&(s=!0,e={type:p,params:[e],async:!1}),!s)){if(this.context.isBindingElement||this.throwUnexpectedToken(this.lookahead),e.type===c.Syntax.SequenceExpression)for(n=0;n")){for(var c=0;c0){this.nextToken(),this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1;for(var r=[e,this.lookahead],n=t,a=this.isolateCoverGrammar(this.parseExponentiationExpression),c=[n,i.value,a],l=[s];!((s=this.binaryPrecedence(this.lookahead))<=0);){for(;c.length>2&&s<=l[l.length-1];){a=c.pop();var p=c.pop();l.pop(),n=c.pop(),r.pop();var A=this.startNode(r[r.length-1]);c.push(this.finalize(A,new o.BinaryExpression(p,n,a)))}c.push(this.nextToken().value),l.push(s),r.push(this.lookahead),c.push(this.isolateCoverGrammar(this.parseExponentiationExpression))}var u=c.length-1;t=c[u];for(var d=r.pop();u>1;){var h=r.pop(),m=d&&d.lineStart;A=this.startNode(h,m),p=c[u-1],t=this.finalize(A,new o.BinaryExpression(p,c[u-2],t)),u-=2,d=h}}return t},e.prototype.parseConditionalExpression=function(){var e=this.lookahead,t=this.inheritCoverGrammar(this.parseBinaryExpression);if(this.match("?")){this.nextToken();var i=this.context.allowIn;this.context.allowIn=!0;var s=this.isolateCoverGrammar(this.parseAssignmentExpression);this.context.allowIn=i,this.expect(":");var r=this.isolateCoverGrammar(this.parseAssignmentExpression);t=this.finalize(this.startNode(e),new o.ConditionalExpression(t,s,r)),this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1}return t},e.prototype.checkPatternParam=function(e,t){switch(t.type){case c.Syntax.Identifier:this.validateParam(e,t,t.name);break;case c.Syntax.RestElement:this.checkPatternParam(e,t.argument);break;case c.Syntax.AssignmentPattern:this.checkPatternParam(e,t.left);break;case c.Syntax.ArrayPattern:for(var i=0;i")){this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1;var r=e.async,a=this.reinterpretAsCoverFormalsList(e);if(a){this.hasLineTerminator&&this.tolerateUnexpectedToken(this.lookahead),this.context.firstCoverInitializedNameError=null;var l=this.context.strict,A=this.context.allowStrictDirective;this.context.allowStrictDirective=a.simple;var u=this.context.allowYield,d=this.context.await;this.context.allowYield=!0,this.context.await=r;var h=this.startNode(t);this.expect("=>");var m=void 0;if(this.match("{")){var g=this.context.allowIn;this.context.allowIn=!0,m=this.parseFunctionSourceElements(),this.context.allowIn=g}else m=this.isolateCoverGrammar(this.parseAssignmentExpression);var f=m.type!==c.Syntax.BlockStatement;this.context.strict&&a.firstRestricted&&this.throwUnexpectedToken(a.firstRestricted,a.message),this.context.strict&&a.stricted&&this.tolerateUnexpectedToken(a.stricted,a.message),e=r?this.finalize(h,new o.AsyncArrowFunctionExpression(a.params,m,f)):this.finalize(h,new o.ArrowFunctionExpression(a.params,m,f)),this.context.strict=l,this.context.allowStrictDirective=A,this.context.allowYield=u,this.context.await=d}}else if(this.matchAssign()){if(this.context.isAssignmentTarget||this.tolerateError(n.Messages.InvalidLHSInAssignment),this.context.strict&&e.type===c.Syntax.Identifier){var E=e;this.scanner.isRestrictedWord(E.name)&&this.tolerateUnexpectedToken(i,n.Messages.StrictLHSAssignment),this.scanner.isStrictModeReservedWord(E.name)&&this.tolerateUnexpectedToken(i,n.Messages.StrictReservedWord)}this.match("=")?this.reinterpretExpressionAsPattern(e):(this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1);var C=(i=this.nextToken()).value,y=this.isolateCoverGrammar(this.parseAssignmentExpression);e=this.finalize(this.startNode(t),new o.AssignmentExpression(C,e,y)),this.context.firstCoverInitializedNameError=null}}return e},e.prototype.parseExpression=function(){var e=this.lookahead,t=this.isolateCoverGrammar(this.parseAssignmentExpression);if(this.match(",")){var i=[];for(i.push(t);2!==this.lookahead.type&&this.match(",");)this.nextToken(),i.push(this.isolateCoverGrammar(this.parseAssignmentExpression));t=this.finalize(this.startNode(e),new o.SequenceExpression(i))}return t},e.prototype.parseStatementListItem=function(){var e;if(this.context.isAssignmentTarget=!0,this.context.isBindingElement=!0,4===this.lookahead.type)switch(this.lookahead.value){case"export":this.context.isModule||this.tolerateUnexpectedToken(this.lookahead,n.Messages.IllegalExportDeclaration),e=this.parseExportDeclaration();break;case"import":this.context.isModule||this.tolerateUnexpectedToken(this.lookahead,n.Messages.IllegalImportDeclaration),e=this.parseImportDeclaration();break;case"const":e=this.parseLexicalDeclaration({inFor:!1});break;case"function":e=this.parseFunctionDeclaration();break;case"class":e=this.parseClassDeclaration();break;case"let":e=this.isLexicalDeclaration()?this.parseLexicalDeclaration({inFor:!1}):this.parseStatement();break;default:e=this.parseStatement()}else e=this.parseStatement();return e},e.prototype.parseBlock=function(){var e=this.createNode();this.expect("{");for(var t=[];!this.match("}");)t.push(this.parseStatementListItem());return this.expect("}"),this.finalize(e,new o.BlockStatement(t))},e.prototype.parseLexicalBinding=function(e,t){var i=this.createNode(),s=this.parsePattern([],e);this.context.strict&&s.type===c.Syntax.Identifier&&this.scanner.isRestrictedWord(s.name)&&this.tolerateError(n.Messages.StrictVarName);var r=null;return"const"===e?this.matchKeyword("in")||this.matchContextualKeyword("of")||(this.match("=")?(this.nextToken(),r=this.isolateCoverGrammar(this.parseAssignmentExpression)):this.throwError(n.Messages.DeclarationMissingInitializer,"const")):(!t.inFor&&s.type!==c.Syntax.Identifier||this.match("="))&&(this.expect("="),r=this.isolateCoverGrammar(this.parseAssignmentExpression)),this.finalize(i,new o.VariableDeclarator(s,r))},e.prototype.parseBindingList=function(e,t){for(var i=[this.parseLexicalBinding(e,t)];this.match(",");)this.nextToken(),i.push(this.parseLexicalBinding(e,t));return i},e.prototype.isLexicalDeclaration=function(){var e=this.scanner.saveState();this.scanner.scanComments();var t=this.scanner.lex();return this.scanner.restoreState(e),3===t.type||7===t.type&&"["===t.value||7===t.type&&"{"===t.value||4===t.type&&"let"===t.value||4===t.type&&"yield"===t.value},e.prototype.parseLexicalDeclaration=function(e){var t=this.createNode(),i=this.nextToken().value;s.assert("let"===i||"const"===i,"Lexical declaration must be either let or const");var r=this.parseBindingList(i,e);return this.consumeSemicolon(),this.finalize(t,new o.VariableDeclaration(r,i))},e.prototype.parseBindingRestElement=function(e,t){var i=this.createNode();this.expect("...");var s=this.parsePattern(e,t);return this.finalize(i,new o.RestElement(s))},e.prototype.parseArrayPattern=function(e,t){var i=this.createNode();this.expect("[");for(var s=[];!this.match("]");)if(this.match(","))this.nextToken(),s.push(null);else{if(this.match("...")){s.push(this.parseBindingRestElement(e,t));break}s.push(this.parsePatternWithDefault(e,t)),this.match("]")||this.expect(",")}return this.expect("]"),this.finalize(i,new o.ArrayPattern(s))},e.prototype.parsePropertyPattern=function(e,t){var i,s,r=this.createNode(),n=!1,a=!1;if(3===this.lookahead.type){var c=this.lookahead;i=this.parseVariableIdentifier();var l=this.finalize(r,new o.Identifier(c.value));if(this.match("=")){e.push(c),a=!0,this.nextToken();var p=this.parseAssignmentExpression();s=this.finalize(this.startNode(c),new o.AssignmentPattern(l,p))}else this.match(":")?(this.expect(":"),s=this.parsePatternWithDefault(e,t)):(e.push(c),a=!0,s=l)}else n=this.match("["),i=this.parseObjectPropertyKey(),this.expect(":"),s=this.parsePatternWithDefault(e,t);return this.finalize(r,new o.Property("init",i,n,s,!1,a))},e.prototype.parseObjectPattern=function(e,t){var i=this.createNode(),s=[];for(this.expect("{");!this.match("}");)s.push(this.parsePropertyPattern(e,t)),this.match("}")||this.expect(",");return this.expect("}"),this.finalize(i,new o.ObjectPattern(s))},e.prototype.parsePattern=function(e,t){var i;return this.match("[")?i=this.parseArrayPattern(e,t):this.match("{")?i=this.parseObjectPattern(e,t):(!this.matchKeyword("let")||"const"!==t&&"let"!==t||this.tolerateUnexpectedToken(this.lookahead,n.Messages.LetInLexicalBinding),e.push(this.lookahead),i=this.parseVariableIdentifier(t)),i},e.prototype.parsePatternWithDefault=function(e,t){var i=this.lookahead,s=this.parsePattern(e,t);if(this.match("=")){this.nextToken();var r=this.context.allowYield;this.context.allowYield=!0;var n=this.isolateCoverGrammar(this.parseAssignmentExpression);this.context.allowYield=r,s=this.finalize(this.startNode(i),new o.AssignmentPattern(s,n))}return s},e.prototype.parseVariableIdentifier=function(e){var t=this.createNode(),i=this.nextToken();return 4===i.type&&"yield"===i.value?this.context.strict?this.tolerateUnexpectedToken(i,n.Messages.StrictReservedWord):this.context.allowYield||this.throwUnexpectedToken(i):3!==i.type?this.context.strict&&4===i.type&&this.scanner.isStrictModeReservedWord(i.value)?this.tolerateUnexpectedToken(i,n.Messages.StrictReservedWord):(this.context.strict||"let"!==i.value||"var"!==e)&&this.throwUnexpectedToken(i):(this.context.isModule||this.context.await)&&3===i.type&&"await"===i.value&&this.tolerateUnexpectedToken(i),this.finalize(t,new o.Identifier(i.value))},e.prototype.parseVariableDeclaration=function(e){var t=this.createNode(),i=this.parsePattern([],"var");this.context.strict&&i.type===c.Syntax.Identifier&&this.scanner.isRestrictedWord(i.name)&&this.tolerateError(n.Messages.StrictVarName);var s=null;return this.match("=")?(this.nextToken(),s=this.isolateCoverGrammar(this.parseAssignmentExpression)):i.type===c.Syntax.Identifier||e.inFor||this.expect("="),this.finalize(t,new o.VariableDeclarator(i,s))},e.prototype.parseVariableDeclarationList=function(e){var t={inFor:e.inFor},i=[];for(i.push(this.parseVariableDeclaration(t));this.match(",");)this.nextToken(),i.push(this.parseVariableDeclaration(t));return i},e.prototype.parseVariableStatement=function(){var e=this.createNode();this.expectKeyword("var");var t=this.parseVariableDeclarationList({inFor:!1});return this.consumeSemicolon(),this.finalize(e,new o.VariableDeclaration(t,"var"))},e.prototype.parseEmptyStatement=function(){var e=this.createNode();return this.expect(";"),this.finalize(e,new o.EmptyStatement)},e.prototype.parseExpressionStatement=function(){var e=this.createNode(),t=this.parseExpression();return this.consumeSemicolon(),this.finalize(e,new o.ExpressionStatement(t))},e.prototype.parseIfClause=function(){return this.context.strict&&this.matchKeyword("function")&&this.tolerateError(n.Messages.StrictFunction),this.parseStatement()},e.prototype.parseIfStatement=function(){var e,t=this.createNode(),i=null;this.expectKeyword("if"),this.expect("(");var s=this.parseExpression();return!this.match(")")&&this.config.tolerant?(this.tolerateUnexpectedToken(this.nextToken()),e=this.finalize(this.createNode(),new o.EmptyStatement)):(this.expect(")"),e=this.parseIfClause(),this.matchKeyword("else")&&(this.nextToken(),i=this.parseIfClause())),this.finalize(t,new o.IfStatement(s,e,i))},e.prototype.parseDoWhileStatement=function(){var e=this.createNode();this.expectKeyword("do");var t=this.context.inIteration;this.context.inIteration=!0;var i=this.parseStatement();this.context.inIteration=t,this.expectKeyword("while"),this.expect("(");var s=this.parseExpression();return!this.match(")")&&this.config.tolerant?this.tolerateUnexpectedToken(this.nextToken()):(this.expect(")"),this.match(";")&&this.nextToken()),this.finalize(e,new o.DoWhileStatement(i,s))},e.prototype.parseWhileStatement=function(){var e,t=this.createNode();this.expectKeyword("while"),this.expect("(");var i=this.parseExpression();if(!this.match(")")&&this.config.tolerant)this.tolerateUnexpectedToken(this.nextToken()),e=this.finalize(this.createNode(),new o.EmptyStatement);else{this.expect(")");var s=this.context.inIteration;this.context.inIteration=!0,e=this.parseStatement(),this.context.inIteration=s}return this.finalize(t,new o.WhileStatement(i,e))},e.prototype.parseForStatement=function(){var e,t,i,s=null,r=null,a=null,l=!0,p=this.createNode();if(this.expectKeyword("for"),this.expect("("),this.match(";"))this.nextToken();else if(this.matchKeyword("var")){s=this.createNode(),this.nextToken();var A=this.context.allowIn;this.context.allowIn=!1;var u=this.parseVariableDeclarationList({inFor:!0});if(this.context.allowIn=A,1===u.length&&this.matchKeyword("in")){var d=u[0];d.init&&(d.id.type===c.Syntax.ArrayPattern||d.id.type===c.Syntax.ObjectPattern||this.context.strict)&&this.tolerateError(n.Messages.ForInOfLoopInitializer,"for-in"),s=this.finalize(s,new o.VariableDeclaration(u,"var")),this.nextToken(),e=s,t=this.parseExpression(),s=null}else 1===u.length&&null===u[0].init&&this.matchContextualKeyword("of")?(s=this.finalize(s,new o.VariableDeclaration(u,"var")),this.nextToken(),e=s,t=this.parseAssignmentExpression(),s=null,l=!1):(s=this.finalize(s,new o.VariableDeclaration(u,"var")),this.expect(";"))}else if(this.matchKeyword("const")||this.matchKeyword("let")){s=this.createNode();var h=this.nextToken().value;this.context.strict||"in"!==this.lookahead.value?(A=this.context.allowIn,this.context.allowIn=!1,u=this.parseBindingList(h,{inFor:!0}),this.context.allowIn=A,1===u.length&&null===u[0].init&&this.matchKeyword("in")?(s=this.finalize(s,new o.VariableDeclaration(u,h)),this.nextToken(),e=s,t=this.parseExpression(),s=null):1===u.length&&null===u[0].init&&this.matchContextualKeyword("of")?(s=this.finalize(s,new o.VariableDeclaration(u,h)),this.nextToken(),e=s,t=this.parseAssignmentExpression(),s=null,l=!1):(this.consumeSemicolon(),s=this.finalize(s,new o.VariableDeclaration(u,h)))):(s=this.finalize(s,new o.Identifier(h)),this.nextToken(),e=s,t=this.parseExpression(),s=null)}else{var m=this.lookahead;if(A=this.context.allowIn,this.context.allowIn=!1,s=this.inheritCoverGrammar(this.parseAssignmentExpression),this.context.allowIn=A,this.matchKeyword("in"))this.context.isAssignmentTarget&&s.type!==c.Syntax.AssignmentExpression||this.tolerateError(n.Messages.InvalidLHSInForIn),this.nextToken(),this.reinterpretExpressionAsPattern(s),e=s,t=this.parseExpression(),s=null;else if(this.matchContextualKeyword("of"))this.context.isAssignmentTarget&&s.type!==c.Syntax.AssignmentExpression||this.tolerateError(n.Messages.InvalidLHSInForLoop),this.nextToken(),this.reinterpretExpressionAsPattern(s),e=s,t=this.parseAssignmentExpression(),s=null,l=!1;else{if(this.match(",")){for(var g=[s];this.match(",");)this.nextToken(),g.push(this.isolateCoverGrammar(this.parseAssignmentExpression));s=this.finalize(this.startNode(m),new o.SequenceExpression(g))}this.expect(";")}}if(void 0===e&&(this.match(";")||(r=this.parseExpression()),this.expect(";"),this.match(")")||(a=this.parseExpression())),!this.match(")")&&this.config.tolerant)this.tolerateUnexpectedToken(this.nextToken()),i=this.finalize(this.createNode(),new o.EmptyStatement);else{this.expect(")");var f=this.context.inIteration;this.context.inIteration=!0,i=this.isolateCoverGrammar(this.parseStatement),this.context.inIteration=f}return void 0===e?this.finalize(p,new o.ForStatement(s,r,a,i)):l?this.finalize(p,new o.ForInStatement(e,t,i)):this.finalize(p,new o.ForOfStatement(e,t,i))},e.prototype.parseContinueStatement=function(){var e=this.createNode();this.expectKeyword("continue");var t=null;if(3===this.lookahead.type&&!this.hasLineTerminator){var i=this.parseVariableIdentifier();t=i;var s="$"+i.name;Object.prototype.hasOwnProperty.call(this.context.labelSet,s)||this.throwError(n.Messages.UnknownLabel,i.name)}return this.consumeSemicolon(),null!==t||this.context.inIteration||this.throwError(n.Messages.IllegalContinue),this.finalize(e,new o.ContinueStatement(t))},e.prototype.parseBreakStatement=function(){var e=this.createNode();this.expectKeyword("break");var t=null;if(3===this.lookahead.type&&!this.hasLineTerminator){var i=this.parseVariableIdentifier(),s="$"+i.name;Object.prototype.hasOwnProperty.call(this.context.labelSet,s)||this.throwError(n.Messages.UnknownLabel,i.name),t=i}return this.consumeSemicolon(),null!==t||this.context.inIteration||this.context.inSwitch||this.throwError(n.Messages.IllegalBreak),this.finalize(e,new o.BreakStatement(t))},e.prototype.parseReturnStatement=function(){this.context.inFunctionBody||this.tolerateError(n.Messages.IllegalReturn);var e=this.createNode();this.expectKeyword("return");var t=(this.match(";")||this.match("}")||this.hasLineTerminator||2===this.lookahead.type)&&8!==this.lookahead.type&&10!==this.lookahead.type?null:this.parseExpression();return this.consumeSemicolon(),this.finalize(e,new o.ReturnStatement(t))},e.prototype.parseWithStatement=function(){this.context.strict&&this.tolerateError(n.Messages.StrictModeWith);var e,t=this.createNode();this.expectKeyword("with"),this.expect("(");var i=this.parseExpression();return!this.match(")")&&this.config.tolerant?(this.tolerateUnexpectedToken(this.nextToken()),e=this.finalize(this.createNode(),new o.EmptyStatement)):(this.expect(")"),e=this.parseStatement()),this.finalize(t,new o.WithStatement(i,e))},e.prototype.parseSwitchCase=function(){var e,t=this.createNode();this.matchKeyword("default")?(this.nextToken(),e=null):(this.expectKeyword("case"),e=this.parseExpression()),this.expect(":");for(var i=[];!(this.match("}")||this.matchKeyword("default")||this.matchKeyword("case"));)i.push(this.parseStatementListItem());return this.finalize(t,new o.SwitchCase(e,i))},e.prototype.parseSwitchStatement=function(){var e=this.createNode();this.expectKeyword("switch"),this.expect("(");var t=this.parseExpression();this.expect(")");var i=this.context.inSwitch;this.context.inSwitch=!0;var s=[],r=!1;for(this.expect("{");!this.match("}");){var a=this.parseSwitchCase();null===a.test&&(r&&this.throwError(n.Messages.MultipleDefaultsInSwitch),r=!0),s.push(a)}return this.expect("}"),this.context.inSwitch=i,this.finalize(e,new o.SwitchStatement(t,s))},e.prototype.parseLabelledStatement=function(){var e,t=this.createNode(),i=this.parseExpression();if(i.type===c.Syntax.Identifier&&this.match(":")){this.nextToken();var s=i,r="$"+s.name;Object.prototype.hasOwnProperty.call(this.context.labelSet,r)&&this.throwError(n.Messages.Redeclaration,"Label",s.name),this.context.labelSet[r]=!0;var a=void 0;if(this.matchKeyword("class"))this.tolerateUnexpectedToken(this.lookahead),a=this.parseClassDeclaration();else if(this.matchKeyword("function")){var l=this.lookahead,p=this.parseFunctionDeclaration();this.context.strict?this.tolerateUnexpectedToken(l,n.Messages.StrictFunction):p.generator&&this.tolerateUnexpectedToken(l,n.Messages.GeneratorInLegacyContext),a=p}else a=this.parseStatement();delete this.context.labelSet[r],e=new o.LabeledStatement(s,a)}else this.consumeSemicolon(),e=new o.ExpressionStatement(i);return this.finalize(t,e)},e.prototype.parseThrowStatement=function(){var e=this.createNode();this.expectKeyword("throw"),this.hasLineTerminator&&this.throwError(n.Messages.NewlineAfterThrow);var t=this.parseExpression();return this.consumeSemicolon(),this.finalize(e,new o.ThrowStatement(t))},e.prototype.parseCatchClause=function(){var e=this.createNode();this.expectKeyword("catch"),this.expect("("),this.match(")")&&this.throwUnexpectedToken(this.lookahead);for(var t=[],i=this.parsePattern(t),s={},r=0;r0&&this.tolerateError(n.Messages.BadGetterArity);var s=this.parsePropertyMethod(i);return this.context.allowYield=t,this.finalize(e,new o.FunctionExpression(null,i.params,s,!1))},e.prototype.parseSetterMethod=function(){var e=this.createNode(),t=this.context.allowYield;this.context.allowYield=!0;var i=this.parseFormalParameters();1!==i.params.length?this.tolerateError(n.Messages.BadSetterArity):i.params[0]instanceof o.RestElement&&this.tolerateError(n.Messages.BadSetterRestParameter);var s=this.parsePropertyMethod(i);return this.context.allowYield=t,this.finalize(e,new o.FunctionExpression(null,i.params,s,!1))},e.prototype.parseGeneratorMethod=function(){var e=this.createNode(),t=this.context.allowYield;this.context.allowYield=!0;var i=this.parseFormalParameters();this.context.allowYield=!1;var s=this.parsePropertyMethod(i);return this.context.allowYield=t,this.finalize(e,new o.FunctionExpression(null,i.params,s,!0))},e.prototype.isStartOfExpression=function(){var e=!0,t=this.lookahead.value;switch(this.lookahead.type){case 7:e="["===t||"("===t||"{"===t||"+"===t||"-"===t||"!"===t||"~"===t||"++"===t||"--"===t||"/"===t||"/="===t;break;case 4:e="class"===t||"delete"===t||"function"===t||"let"===t||"new"===t||"super"===t||"this"===t||"typeof"===t||"void"===t||"yield"===t}return e},e.prototype.parseYieldExpression=function(){var e=this.createNode();this.expectKeyword("yield");var t=null,i=!1;if(!this.hasLineTerminator){var s=this.context.allowYield;this.context.allowYield=!1,(i=this.match("*"))?(this.nextToken(),t=this.parseAssignmentExpression()):this.isStartOfExpression()&&(t=this.parseAssignmentExpression()),this.context.allowYield=s}return this.finalize(e,new o.YieldExpression(t,i))},e.prototype.parseClassElement=function(e){var t=this.lookahead,i=this.createNode(),s="",r=null,a=null,c=!1,l=!1,p=!1,A=!1;if(this.match("*"))this.nextToken();else if(c=this.match("["),"static"===(r=this.parseObjectPropertyKey()).name&&(this.qualifiedPropertyName(this.lookahead)||this.match("*"))&&(t=this.lookahead,p=!0,c=this.match("["),this.match("*")?this.nextToken():r=this.parseObjectPropertyKey()),3===t.type&&!this.hasLineTerminator&&"async"===t.value){var u=this.lookahead.value;":"!==u&&"("!==u&&"*"!==u&&(A=!0,t=this.lookahead,r=this.parseObjectPropertyKey(),3===t.type&&"constructor"===t.value&&this.tolerateUnexpectedToken(t,n.Messages.ConstructorIsAsync))}var d=this.qualifiedPropertyName(this.lookahead);return 3===t.type?"get"===t.value&&d?(s="get",c=this.match("["),r=this.parseObjectPropertyKey(),this.context.allowYield=!1,a=this.parseGetterMethod()):"set"===t.value&&d&&(s="set",c=this.match("["),r=this.parseObjectPropertyKey(),a=this.parseSetterMethod()):7===t.type&&"*"===t.value&&d&&(s="init",c=this.match("["),r=this.parseObjectPropertyKey(),a=this.parseGeneratorMethod(),l=!0),!s&&r&&this.match("(")&&(s="init",a=A?this.parsePropertyMethodAsyncFunction():this.parsePropertyMethodFunction(),l=!0),s||this.throwUnexpectedToken(this.lookahead),"init"===s&&(s="method"),c||(p&&this.isPropertyKey(r,"prototype")&&this.throwUnexpectedToken(t,n.Messages.StaticPrototype),!p&&this.isPropertyKey(r,"constructor")&&(("method"!==s||!l||a&&a.generator)&&this.throwUnexpectedToken(t,n.Messages.ConstructorSpecialMethod),e.value?this.throwUnexpectedToken(t,n.Messages.DuplicateConstructor):e.value=!0,s="constructor")),this.finalize(i,new o.MethodDefinition(r,c,a,s,p))},e.prototype.parseClassElementList=function(){var e=[],t={value:!1};for(this.expect("{");!this.match("}");)this.match(";")?this.nextToken():e.push(this.parseClassElement(t));return this.expect("}"),e},e.prototype.parseClassBody=function(){var e=this.createNode(),t=this.parseClassElementList();return this.finalize(e,new o.ClassBody(t))},e.prototype.parseClassDeclaration=function(e){var t=this.createNode(),i=this.context.strict;this.context.strict=!0,this.expectKeyword("class");var s=e&&3!==this.lookahead.type?null:this.parseVariableIdentifier(),r=null;this.matchKeyword("extends")&&(this.nextToken(),r=this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall));var n=this.parseClassBody();return this.context.strict=i,this.finalize(t,new o.ClassDeclaration(s,r,n))},e.prototype.parseClassExpression=function(){var e=this.createNode(),t=this.context.strict;this.context.strict=!0,this.expectKeyword("class");var i=3===this.lookahead.type?this.parseVariableIdentifier():null,s=null;this.matchKeyword("extends")&&(this.nextToken(),s=this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall));var r=this.parseClassBody();return this.context.strict=t,this.finalize(e,new o.ClassExpression(i,s,r))},e.prototype.parseModule=function(){this.context.strict=!0,this.context.isModule=!0,this.scanner.isModule=!0;for(var e=this.createNode(),t=this.parseDirectivePrologues();2!==this.lookahead.type;)t.push(this.parseStatementListItem());return this.finalize(e,new o.Module(t))},e.prototype.parseScript=function(){for(var e=this.createNode(),t=this.parseDirectivePrologues();2!==this.lookahead.type;)t.push(this.parseStatementListItem());return this.finalize(e,new o.Script(t))},e.prototype.parseModuleSpecifier=function(){var e=this.createNode();8!==this.lookahead.type&&this.throwError(n.Messages.InvalidModuleSpecifier);var t=this.nextToken(),i=this.getTokenRaw(t);return this.finalize(e,new o.Literal(t.value,i))},e.prototype.parseImportSpecifier=function(){var e,t,i=this.createNode();return 3===this.lookahead.type?(t=e=this.parseVariableIdentifier(),this.matchContextualKeyword("as")&&(this.nextToken(),t=this.parseVariableIdentifier())):(t=e=this.parseIdentifierName(),this.matchContextualKeyword("as")?(this.nextToken(),t=this.parseVariableIdentifier()):this.throwUnexpectedToken(this.nextToken())),this.finalize(i,new o.ImportSpecifier(t,e))},e.prototype.parseNamedImports=function(){this.expect("{");for(var e=[];!this.match("}");)e.push(this.parseImportSpecifier()),this.match("}")||this.expect(",");return this.expect("}"),e},e.prototype.parseImportDefaultSpecifier=function(){var e=this.createNode(),t=this.parseIdentifierName();return this.finalize(e,new o.ImportDefaultSpecifier(t))},e.prototype.parseImportNamespaceSpecifier=function(){var e=this.createNode();this.expect("*"),this.matchContextualKeyword("as")||this.throwError(n.Messages.NoAsAfterImportNamespace),this.nextToken();var t=this.parseIdentifierName();return this.finalize(e,new o.ImportNamespaceSpecifier(t))},e.prototype.parseImportDeclaration=function(){this.context.inFunctionBody&&this.throwError(n.Messages.IllegalImportDeclaration);var e,t=this.createNode();this.expectKeyword("import");var i=[];if(8===this.lookahead.type)e=this.parseModuleSpecifier();else{if(this.match("{")?i=i.concat(this.parseNamedImports()):this.match("*")?i.push(this.parseImportNamespaceSpecifier()):this.isIdentifierName(this.lookahead)&&!this.matchKeyword("default")?(i.push(this.parseImportDefaultSpecifier()),this.match(",")&&(this.nextToken(),this.match("*")?i.push(this.parseImportNamespaceSpecifier()):this.match("{")?i=i.concat(this.parseNamedImports()):this.throwUnexpectedToken(this.lookahead))):this.throwUnexpectedToken(this.nextToken()),!this.matchContextualKeyword("from")){var s=this.lookahead.value?n.Messages.UnexpectedToken:n.Messages.MissingFromClause;this.throwError(s,this.lookahead.value)}this.nextToken(),e=this.parseModuleSpecifier()}return this.consumeSemicolon(),this.finalize(t,new o.ImportDeclaration(i,e))},e.prototype.parseExportSpecifier=function(){var e=this.createNode(),t=this.parseIdentifierName(),i=t;return this.matchContextualKeyword("as")&&(this.nextToken(),i=this.parseIdentifierName()),this.finalize(e,new o.ExportSpecifier(t,i))},e.prototype.parseExportDeclaration=function(){this.context.inFunctionBody&&this.throwError(n.Messages.IllegalExportDeclaration);var e,t=this.createNode();if(this.expectKeyword("export"),this.matchKeyword("default"))if(this.nextToken(),this.matchKeyword("function")){var i=this.parseFunctionDeclaration(!0);e=this.finalize(t,new o.ExportDefaultDeclaration(i))}else this.matchKeyword("class")?(i=this.parseClassDeclaration(!0),e=this.finalize(t,new o.ExportDefaultDeclaration(i))):this.matchContextualKeyword("async")?(i=this.matchAsyncFunction()?this.parseFunctionDeclaration(!0):this.parseAssignmentExpression(),e=this.finalize(t,new o.ExportDefaultDeclaration(i))):(this.matchContextualKeyword("from")&&this.throwError(n.Messages.UnexpectedToken,this.lookahead.value),i=this.match("{")?this.parseObjectInitializer():this.match("[")?this.parseArrayInitializer():this.parseAssignmentExpression(),this.consumeSemicolon(),e=this.finalize(t,new o.ExportDefaultDeclaration(i)));else if(this.match("*")){if(this.nextToken(),!this.matchContextualKeyword("from")){var s=this.lookahead.value?n.Messages.UnexpectedToken:n.Messages.MissingFromClause;this.throwError(s,this.lookahead.value)}this.nextToken();var r=this.parseModuleSpecifier();this.consumeSemicolon(),e=this.finalize(t,new o.ExportAllDeclaration(r))}else if(4===this.lookahead.type){switch(i=void 0,this.lookahead.value){case"let":case"const":i=this.parseLexicalDeclaration({inFor:!1});break;case"var":case"class":case"function":i=this.parseStatementListItem();break;default:this.throwUnexpectedToken(this.lookahead)}e=this.finalize(t,new o.ExportNamedDeclaration(i,[],null))}else if(this.matchAsyncFunction())i=this.parseFunctionDeclaration(),e=this.finalize(t,new o.ExportNamedDeclaration(i,[],null));else{var a=[],c=null,l=!1;for(this.expect("{");!this.match("}");)l=l||this.matchKeyword("default"),a.push(this.parseExportSpecifier()),this.match("}")||this.expect(",");this.expect("}"),this.matchContextualKeyword("from")?(this.nextToken(),c=this.parseModuleSpecifier(),this.consumeSemicolon()):l?(s=this.lookahead.value?n.Messages.UnexpectedToken:n.Messages.MissingFromClause,this.throwError(s,this.lookahead.value)):this.consumeSemicolon(),e=this.finalize(t,new o.ExportNamedDeclaration(null,a,c))}return e},e}();t.Parser=A},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.assert=function(e,t){if(!e)throw new Error("ASSERT: "+t)}},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(){this.errors=[],this.tolerant=!1}return e.prototype.recordError=function(e){this.errors.push(e)},e.prototype.tolerate=function(e){if(!this.tolerant)throw e;this.recordError(e)},e.prototype.constructError=function(e,t){var i=new Error(e);try{throw i}catch(e){Object.create&&Object.defineProperty&&(i=Object.create(e),Object.defineProperty(i,"column",{value:t}))}return i},e.prototype.createError=function(e,t,i,s){var r="Line "+t+": "+s,n=this.constructError(r,i);return n.index=e,n.lineNumber=t,n.description=s,n},e.prototype.throwError=function(e,t,i,s){throw this.createError(e,t,i,s)},e.prototype.tolerateError=function(e,t,i,s){var r=this.createError(e,t,i,s);if(!this.tolerant)throw r;this.recordError(r)},e}();t.ErrorHandler=i},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Messages={BadGetterArity:"Getter must not have any formal parameters",BadSetterArity:"Setter must have exactly one formal parameter",BadSetterRestParameter:"Setter function argument must not be a rest parameter",ConstructorIsAsync:"Class constructor may not be an async method",ConstructorSpecialMethod:"Class constructor may not be an accessor",DeclarationMissingInitializer:"Missing initializer in %0 declaration",DefaultRestParameter:"Unexpected token =",DuplicateBinding:"Duplicate binding %0",DuplicateConstructor:"A class may only have one constructor",DuplicateProtoProperty:"Duplicate __proto__ fields are not allowed in object literals",ForInOfLoopInitializer:"%0 loop variable declaration may not have an initializer",GeneratorInLegacyContext:"Generator declarations are not allowed in legacy contexts",IllegalBreak:"Illegal break statement",IllegalContinue:"Illegal continue statement",IllegalExportDeclaration:"Unexpected token",IllegalImportDeclaration:"Unexpected token",IllegalLanguageModeDirective:"Illegal 'use strict' directive in function with non-simple parameter list",IllegalReturn:"Illegal return statement",InvalidEscapedReservedWord:"Keyword must not contain escaped characters",InvalidHexEscapeSequence:"Invalid hexadecimal escape sequence",InvalidLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",InvalidLHSInForLoop:"Invalid left-hand side in for-loop",InvalidModuleSpecifier:"Unexpected token",InvalidRegExp:"Invalid regular expression",LetInLexicalBinding:"let is disallowed as a lexically bound name",MissingFromClause:"Unexpected token",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NewlineAfterThrow:"Illegal newline after throw",NoAsAfterImportNamespace:"Unexpected token",NoCatchOrFinally:"Missing catch or finally after try",ParameterAfterRestParameter:"Rest parameter must be last formal parameter",Redeclaration:"%0 '%1' has already been declared",StaticPrototype:"Classes may not have static property named prototype",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mode",StrictDelete:"Delete of an unqualified identifier in strict mode.",StrictFunction:"In strict mode code, functions can only be declared at top level or inside a block",StrictFunctionName:"Function name may not be eval or arguments in strict mode",StrictLHSAssignment:"Assignment to eval or arguments is not allowed in strict mode",StrictLHSPostfix:"Postfix increment/decrement may not have eval or arguments operand in strict mode",StrictLHSPrefix:"Prefix increment/decrement may not have eval or arguments operand in strict mode",StrictModeWith:"Strict mode code may not include a with statement",StrictOctalLiteral:"Octal literals are not allowed in strict mode.",StrictParamDupe:"Strict mode function may not have duplicate parameter names",StrictParamName:"Parameter name eval or arguments is not allowed in strict mode",StrictReservedWord:"Use of future reserved word in strict mode",StrictVarName:"Variable name may not be eval or arguments in strict mode",TemplateOctalLiteral:"Octal literals are not allowed in template strings.",UnexpectedEOS:"Unexpected end of input",UnexpectedIdentifier:"Unexpected identifier",UnexpectedNumber:"Unexpected number",UnexpectedReserved:"Unexpected reserved word",UnexpectedString:"Unexpected string",UnexpectedTemplate:"Unexpected quasi %0",UnexpectedToken:"Unexpected token %0",UnexpectedTokenIllegal:"Unexpected token ILLEGAL",UnknownLabel:"Undefined label '%0'",UnterminatedRegExp:"Invalid regular expression: missing /"}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=i(9),r=i(4),n=i(11);function o(e){return"0123456789abcdef".indexOf(e.toLowerCase())}function a(e){return"01234567".indexOf(e)}var c=function(){function e(e,t){this.source=e,this.errorHandler=t,this.trackComment=!1,this.isModule=!1,this.length=e.length,this.index=0,this.lineNumber=e.length>0?1:0,this.lineStart=0,this.curlyStack=[]}return e.prototype.saveState=function(){return{index:this.index,lineNumber:this.lineNumber,lineStart:this.lineStart}},e.prototype.restoreState=function(e){this.index=e.index,this.lineNumber=e.lineNumber,this.lineStart=e.lineStart},e.prototype.eof=function(){return this.index>=this.length},e.prototype.throwUnexpectedToken=function(e){return void 0===e&&(e=n.Messages.UnexpectedTokenIllegal),this.errorHandler.throwError(this.index,this.lineNumber,this.index-this.lineStart+1,e)},e.prototype.tolerateUnexpectedToken=function(e){void 0===e&&(e=n.Messages.UnexpectedTokenIllegal),this.errorHandler.tolerateError(this.index,this.lineNumber,this.index-this.lineStart+1,e)},e.prototype.skipSingleLineComment=function(e){var t,i,s=[];for(this.trackComment&&(s=[],t=this.index-e,i={start:{line:this.lineNumber,column:this.index-this.lineStart-e},end:{}});!this.eof();){var n=this.source.charCodeAt(this.index);if(++this.index,r.Character.isLineTerminator(n)){if(this.trackComment){i.end={line:this.lineNumber,column:this.index-this.lineStart-1};var o={multiLine:!1,slice:[t+e,this.index-1],range:[t,this.index-1],loc:i};s.push(o)}return 13===n&&10===this.source.charCodeAt(this.index)&&++this.index,++this.lineNumber,this.lineStart=this.index,s}}return this.trackComment&&(i.end={line:this.lineNumber,column:this.index-this.lineStart},o={multiLine:!1,slice:[t+e,this.index],range:[t,this.index],loc:i},s.push(o)),s},e.prototype.skipMultiLineComment=function(){var e,t,i=[];for(this.trackComment&&(i=[],e=this.index-2,t={start:{line:this.lineNumber,column:this.index-this.lineStart-2},end:{}});!this.eof();){var s=this.source.charCodeAt(this.index);if(r.Character.isLineTerminator(s))13===s&&10===this.source.charCodeAt(this.index+1)&&++this.index,++this.lineNumber,++this.index,this.lineStart=this.index;else if(42===s){if(47===this.source.charCodeAt(this.index+1)){if(this.index+=2,this.trackComment){t.end={line:this.lineNumber,column:this.index-this.lineStart};var n={multiLine:!0,slice:[e+2,this.index-2],range:[e,this.index],loc:t};i.push(n)}return i}++this.index}else++this.index}return this.trackComment&&(t.end={line:this.lineNumber,column:this.index-this.lineStart},n={multiLine:!0,slice:[e+2,this.index],range:[e,this.index],loc:t},i.push(n)),this.tolerateUnexpectedToken(),i},e.prototype.scanComments=function(){var e;this.trackComment&&(e=[]);for(var t=0===this.index;!this.eof();){var i=this.source.charCodeAt(this.index);if(r.Character.isWhiteSpace(i))++this.index;else if(r.Character.isLineTerminator(i))++this.index,13===i&&10===this.source.charCodeAt(this.index)&&++this.index,++this.lineNumber,this.lineStart=this.index,t=!0;else if(47===i)if(47===(i=this.source.charCodeAt(this.index+1))){this.index+=2;var s=this.skipSingleLineComment(2);this.trackComment&&(e=e.concat(s)),t=!0}else{if(42!==i)break;this.index+=2,s=this.skipMultiLineComment(),this.trackComment&&(e=e.concat(s))}else if(t&&45===i){if(45!==this.source.charCodeAt(this.index+1)||62!==this.source.charCodeAt(this.index+2))break;this.index+=3,s=this.skipSingleLineComment(3),this.trackComment&&(e=e.concat(s))}else{if(60!==i||this.isModule)break;if("!--"!==this.source.slice(this.index+1,this.index+4))break;this.index+=4,s=this.skipSingleLineComment(4),this.trackComment&&(e=e.concat(s))}}return e},e.prototype.isFutureReservedWord=function(e){switch(e){case"enum":case"export":case"import":case"super":return!0;default:return!1}},e.prototype.isStrictModeReservedWord=function(e){switch(e){case"implements":case"interface":case"package":case"private":case"protected":case"public":case"static":case"yield":case"let":return!0;default:return!1}},e.prototype.isRestrictedWord=function(e){return"eval"===e||"arguments"===e},e.prototype.isKeyword=function(e){switch(e.length){case 2:return"if"===e||"in"===e||"do"===e;case 3:return"var"===e||"for"===e||"new"===e||"try"===e||"let"===e;case 4:return"this"===e||"else"===e||"case"===e||"void"===e||"with"===e||"enum"===e;case 5:return"while"===e||"break"===e||"catch"===e||"throw"===e||"const"===e||"yield"===e||"class"===e||"super"===e;case 6:return"return"===e||"typeof"===e||"delete"===e||"switch"===e||"export"===e||"import"===e;case 7:return"default"===e||"finally"===e||"extends"===e;case 8:return"function"===e||"continue"===e||"debugger"===e;case 10:return"instanceof"===e;default:return!1}},e.prototype.codePointAt=function(e){var t=this.source.charCodeAt(e);if(t>=55296&&t<=56319){var i=this.source.charCodeAt(e+1);i>=56320&&i<=57343&&(t=1024*(t-55296)+i-56320+65536)}return t},e.prototype.scanHexEscape=function(e){for(var t="u"===e?4:2,i=0,s=0;s1114111||"}"!==e)&&this.throwUnexpectedToken(),r.Character.fromCodePoint(t)},e.prototype.getIdentifier=function(){for(var e=this.index++;!this.eof();){var t=this.source.charCodeAt(this.index);if(92===t)return this.index=e,this.getComplexIdentifier();if(t>=55296&&t<57343)return this.index=e,this.getComplexIdentifier();if(!r.Character.isIdentifierPart(t))break;++this.index}return this.source.slice(e,this.index)},e.prototype.getComplexIdentifier=function(){var e,t=this.codePointAt(this.index),i=r.Character.fromCodePoint(t);for(this.index+=i.length,92===t&&(117!==this.source.charCodeAt(this.index)&&this.throwUnexpectedToken(),++this.index,"{"===this.source[this.index]?(++this.index,e=this.scanUnicodeCodePointEscape()):null!==(e=this.scanHexEscape("u"))&&"\\"!==e&&r.Character.isIdentifierStart(e.charCodeAt(0))||this.throwUnexpectedToken(),i=e);!this.eof()&&(t=this.codePointAt(this.index),r.Character.isIdentifierPart(t));)i+=e=r.Character.fromCodePoint(t),this.index+=e.length,92===t&&(i=i.substr(0,i.length-1),117!==this.source.charCodeAt(this.index)&&this.throwUnexpectedToken(),++this.index,"{"===this.source[this.index]?(++this.index,e=this.scanUnicodeCodePointEscape()):null!==(e=this.scanHexEscape("u"))&&"\\"!==e&&r.Character.isIdentifierPart(e.charCodeAt(0))||this.throwUnexpectedToken(),i+=e);return i},e.prototype.octalToDecimal=function(e){var t="0"!==e,i=a(e);return!this.eof()&&r.Character.isOctalDigit(this.source.charCodeAt(this.index))&&(t=!0,i=8*i+a(this.source[this.index++]),"0123".indexOf(e)>=0&&!this.eof()&&r.Character.isOctalDigit(this.source.charCodeAt(this.index))&&(i=8*i+a(this.source[this.index++]))),{code:i,octal:t}},e.prototype.scanIdentifier=function(){var e,t=this.index,i=92===this.source.charCodeAt(t)?this.getComplexIdentifier():this.getIdentifier();if(3!=(e=1===i.length?3:this.isKeyword(i)?4:"null"===i?5:"true"===i||"false"===i?1:3)&&t+i.length!==this.index){var s=this.index;this.index=t,this.tolerateUnexpectedToken(n.Messages.InvalidEscapedReservedWord),this.index=s}return{type:e,value:i,lineNumber:this.lineNumber,lineStart:this.lineStart,start:t,end:this.index}},e.prototype.scanPunctuator=function(){var e=this.index,t=this.source[this.index];switch(t){case"(":case"{":"{"===t&&this.curlyStack.push("{"),++this.index;break;case".":++this.index,"."===this.source[this.index]&&"."===this.source[this.index+1]&&(this.index+=2,t="...");break;case"}":++this.index,this.curlyStack.pop();break;case")":case";":case",":case"[":case"]":case":":case"?":case"~":++this.index;break;default:">>>="===(t=this.source.substr(this.index,4))?this.index+=4:"==="===(t=t.substr(0,3))||"!=="===t||">>>"===t||"<<="===t||">>="===t||"**="===t?this.index+=3:"&&"===(t=t.substr(0,2))||"||"===t||"=="===t||"!="===t||"+="===t||"-="===t||"*="===t||"/="===t||"++"===t||"--"===t||"<<"===t||">>"===t||"&="===t||"|="===t||"^="===t||"%="===t||"<="===t||">="===t||"=>"===t||"**"===t?this.index+=2:(t=this.source[this.index],"<>=!+-*%&|^/".indexOf(t)>=0&&++this.index)}return this.index===e&&this.throwUnexpectedToken(),{type:7,value:t,lineNumber:this.lineNumber,lineStart:this.lineStart,start:e,end:this.index}},e.prototype.scanHexLiteral=function(e){for(var t="";!this.eof()&&r.Character.isHexDigit(this.source.charCodeAt(this.index));)t+=this.source[this.index++];return 0===t.length&&this.throwUnexpectedToken(),r.Character.isIdentifierStart(this.source.charCodeAt(this.index))&&this.throwUnexpectedToken(),{type:6,value:parseInt("0x"+t,16),lineNumber:this.lineNumber,lineStart:this.lineStart,start:e,end:this.index}},e.prototype.scanBinaryLiteral=function(e){for(var t,i="";!this.eof()&&("0"===(t=this.source[this.index])||"1"===t);)i+=this.source[this.index++];return 0===i.length&&this.throwUnexpectedToken(),this.eof()||(t=this.source.charCodeAt(this.index),(r.Character.isIdentifierStart(t)||r.Character.isDecimalDigit(t))&&this.throwUnexpectedToken()),{type:6,value:parseInt(i,2),lineNumber:this.lineNumber,lineStart:this.lineStart,start:e,end:this.index}},e.prototype.scanOctalLiteral=function(e,t){var i="",s=!1;for(r.Character.isOctalDigit(e.charCodeAt(0))?(s=!0,i="0"+this.source[this.index++]):++this.index;!this.eof()&&r.Character.isOctalDigit(this.source.charCodeAt(this.index));)i+=this.source[this.index++];return s||0!==i.length||this.throwUnexpectedToken(),(r.Character.isIdentifierStart(this.source.charCodeAt(this.index))||r.Character.isDecimalDigit(this.source.charCodeAt(this.index)))&&this.throwUnexpectedToken(),{type:6,value:parseInt(i,8),octal:s,lineNumber:this.lineNumber,lineStart:this.lineStart,start:t,end:this.index}},e.prototype.isImplicitOctalLiteral=function(){for(var e=this.index+1;e=0&&(i=i.replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g,(function(e,t,i){var r=parseInt(t||i,16);return r>1114111&&s.throwUnexpectedToken(n.Messages.InvalidRegExp),r<=65535?String.fromCharCode(r):"￿"})).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,"￿"));try{RegExp(i)}catch(e){this.throwUnexpectedToken(n.Messages.InvalidRegExp)}try{return new RegExp(e,t)}catch(e){return null}},e.prototype.scanRegExpBody=function(){var e=this.source[this.index];s.assert("/"===e,"Regular expression literal must start with a slash");for(var t=this.source[this.index++],i=!1,o=!1;!this.eof();)if(t+=e=this.source[this.index++],"\\"===e)e=this.source[this.index++],r.Character.isLineTerminator(e.charCodeAt(0))&&this.throwUnexpectedToken(n.Messages.UnterminatedRegExp),t+=e;else if(r.Character.isLineTerminator(e.charCodeAt(0)))this.throwUnexpectedToken(n.Messages.UnterminatedRegExp);else if(i)"]"===e&&(i=!1);else{if("/"===e){o=!0;break}"["===e&&(i=!0)}return o||this.throwUnexpectedToken(n.Messages.UnterminatedRegExp),t.substr(1,t.length-2)},e.prototype.scanRegExpFlags=function(){for(var e="";!this.eof();){var t=this.source[this.index];if(!r.Character.isIdentifierPart(t.charCodeAt(0)))break;if(++this.index,"\\"!==t||this.eof())e+=t;else if("u"===(t=this.source[this.index])){++this.index;var i=this.index,s=this.scanHexEscape("u");if(null!==s)for(e+=s;i=55296&&e<57343&&r.Character.isIdentifierStart(this.codePointAt(this.index))?this.scanIdentifier():this.scanPunctuator()},e}();t.Scanner=c},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TokenName={},t.TokenName[1]="Boolean",t.TokenName[2]="",t.TokenName[3]="Identifier",t.TokenName[4]="Keyword",t.TokenName[5]="Null",t.TokenName[6]="Numeric",t.TokenName[7]="Punctuator",t.TokenName[8]="String",t.TokenName[9]="RegularExpression",t.TokenName[10]="Template"},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.XHTMLEntities={quot:'"',amp:"&",apos:"'",gt:">",nbsp:" ",iexcl:"¡",cent:"¢",pound:"£",curren:"¤",yen:"¥",brvbar:"¦",sect:"§",uml:"¨",copy:"©",ordf:"ª",laquo:"«",not:"¬",shy:"­",reg:"®",macr:"¯",deg:"°",plusmn:"±",sup2:"²",sup3:"³",acute:"´",micro:"µ",para:"¶",middot:"·",cedil:"¸",sup1:"¹",ordm:"º",raquo:"»",frac14:"¼",frac12:"½",frac34:"¾",iquest:"¿",Agrave:"À",Aacute:"Á",Acirc:"Â",Atilde:"Ã",Auml:"Ä",Aring:"Å",AElig:"Æ",Ccedil:"Ç",Egrave:"È",Eacute:"É",Ecirc:"Ê",Euml:"Ë",Igrave:"Ì",Iacute:"Í",Icirc:"Î",Iuml:"Ï",ETH:"Ð",Ntilde:"Ñ",Ograve:"Ò",Oacute:"Ó",Ocirc:"Ô",Otilde:"Õ",Ouml:"Ö",times:"×",Oslash:"Ø",Ugrave:"Ù",Uacute:"Ú",Ucirc:"Û",Uuml:"Ü",Yacute:"Ý",THORN:"Þ",szlig:"ß",agrave:"à",aacute:"á",acirc:"â",atilde:"ã",auml:"ä",aring:"å",aelig:"æ",ccedil:"ç",egrave:"è",eacute:"é",ecirc:"ê",euml:"ë",igrave:"ì",iacute:"í",icirc:"î",iuml:"ï",eth:"ð",ntilde:"ñ",ograve:"ò",oacute:"ó",ocirc:"ô",otilde:"õ",ouml:"ö",divide:"÷",oslash:"ø",ugrave:"ù",uacute:"ú",ucirc:"û",uuml:"ü",yacute:"ý",thorn:"þ",yuml:"ÿ",OElig:"Œ",oelig:"œ",Scaron:"Š",scaron:"š",Yuml:"Ÿ",fnof:"ƒ",circ:"ˆ",tilde:"˜",Alpha:"Α",Beta:"Β",Gamma:"Γ",Delta:"Δ",Epsilon:"Ε",Zeta:"Ζ",Eta:"Η",Theta:"Θ",Iota:"Ι",Kappa:"Κ",Lambda:"Λ",Mu:"Μ",Nu:"Ν",Xi:"Ξ",Omicron:"Ο",Pi:"Π",Rho:"Ρ",Sigma:"Σ",Tau:"Τ",Upsilon:"Υ",Phi:"Φ",Chi:"Χ",Psi:"Ψ",Omega:"Ω",alpha:"α",beta:"β",gamma:"γ",delta:"δ",epsilon:"ε",zeta:"ζ",eta:"η",theta:"θ",iota:"ι",kappa:"κ",lambda:"λ",mu:"μ",nu:"ν",xi:"ξ",omicron:"ο",pi:"π",rho:"ρ",sigmaf:"ς",sigma:"σ",tau:"τ",upsilon:"υ",phi:"φ",chi:"χ",psi:"ψ",omega:"ω",thetasym:"ϑ",upsih:"ϒ",piv:"ϖ",ensp:" ",emsp:" ",thinsp:" ",zwnj:"‌",zwj:"‍",lrm:"‎",rlm:"‏",ndash:"–",mdash:"—",lsquo:"‘",rsquo:"’",sbquo:"‚",ldquo:"“",rdquo:"”",bdquo:"„",dagger:"†",Dagger:"‡",bull:"•",hellip:"…",permil:"‰",prime:"′",Prime:"″",lsaquo:"‹",rsaquo:"›",oline:"‾",frasl:"⁄",euro:"€",image:"ℑ",weierp:"℘",real:"ℜ",trade:"™",alefsym:"ℵ",larr:"←",uarr:"↑",rarr:"→",darr:"↓",harr:"↔",crarr:"↵",lArr:"⇐",uArr:"⇑",rArr:"⇒",dArr:"⇓",hArr:"⇔",forall:"∀",part:"∂",exist:"∃",empty:"∅",nabla:"∇",isin:"∈",notin:"∉",ni:"∋",prod:"∏",sum:"∑",minus:"−",lowast:"∗",radic:"√",prop:"∝",infin:"∞",ang:"∠",and:"∧",or:"∨",cap:"∩",cup:"∪",int:"∫",there4:"∴",sim:"∼",cong:"≅",asymp:"≈",ne:"≠",equiv:"≡",le:"≤",ge:"≥",sub:"⊂",sup:"⊃",nsub:"⊄",sube:"⊆",supe:"⊇",oplus:"⊕",otimes:"⊗",perp:"⊥",sdot:"⋅",lceil:"⌈",rceil:"⌉",lfloor:"⌊",rfloor:"⌋",loz:"◊",spades:"♠",clubs:"♣",hearts:"♥",diams:"♦",lang:"⟨",rang:"⟩"}},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=i(10),r=i(12),n=i(13),o=function(){function e(){this.values=[],this.curly=this.paren=-1}return e.prototype.beforeFunctionExpression=function(e){return["(","{","[","in","typeof","instanceof","new","return","case","delete","throw","void","=","+=","-=","*=","**=","/=","%=","<<=",">>=",">>>=","&=","|=","^=",",","+","-","*","**","/","%","++","--","<<",">>",">>>","&","|","^","!","~","&&","||","?",":","===","==",">=","<=","<",">","!=","!=="].indexOf(e)>=0},e.prototype.isRegexStart=function(){var e=this.values[this.values.length-1],t=null!==e;switch(e){case"this":case"]":t=!1;break;case")":var i=this.values[this.paren-1];t="if"===i||"while"===i||"for"===i||"with"===i;break;case"}":if(t=!1,"function"===this.values[this.curly-3])t=!!(s=this.values[this.curly-4])&&!this.beforeFunctionExpression(s);else if("function"===this.values[this.curly-4]){var s;t=!(s=this.values[this.curly-5])||!this.beforeFunctionExpression(s)}}return t},e.prototype.push=function(e){7===e.type||4===e.type?("{"===e.value?this.curly=this.values.length:"("===e.value&&(this.paren=this.values.length),this.values.push(e.value)):this.values.push(null)},e}(),a=function(){function e(e,t){this.errorHandler=new s.ErrorHandler,this.errorHandler.tolerant=!!t&&"boolean"==typeof t.tolerant&&t.tolerant,this.scanner=new r.Scanner(e,this.errorHandler),this.scanner.trackComment=!!t&&"boolean"==typeof t.comment&&t.comment,this.trackRange=!!t&&"boolean"==typeof t.range&&t.range,this.trackLoc=!!t&&"boolean"==typeof t.loc&&t.loc,this.buffer=[],this.reader=new o}return e.prototype.errors=function(){return this.errorHandler.errors},e.prototype.getNextToken=function(){if(0===this.buffer.length){var e=this.scanner.scanComments();if(this.scanner.trackComment)for(var t=0;t{"use strict";var t=Object.prototype.hasOwnProperty,i="~";function s(){}function r(e,t,i){this.fn=e,this.context=t,this.once=i||!1}function n(e,t,s,n,o){if("function"!=typeof s)throw new TypeError("The listener must be a function");var a=new r(s,n||e,o),c=i?i+t:t;return e._events[c]?e._events[c].fn?e._events[c]=[e._events[c],a]:e._events[c].push(a):(e._events[c]=a,e._eventsCount++),e}function o(e,t){0==--e._eventsCount?e._events=new s:delete e._events[t]}function a(){this._events=new s,this._eventsCount=0}Object.create&&(s.prototype=Object.create(null),(new s).__proto__||(i=!1)),a.prototype.eventNames=function(){var e,s,r=[];if(0===this._eventsCount)return r;for(s in e=this._events)t.call(e,s)&&r.push(i?s.slice(1):s);return Object.getOwnPropertySymbols?r.concat(Object.getOwnPropertySymbols(e)):r},a.prototype.listeners=function(e){var t=i?i+e:e,s=this._events[t];if(!s)return[];if(s.fn)return[s.fn];for(var r=0,n=s.length,o=new Array(n);r{"use strict";var t=Object.prototype.hasOwnProperty,i="~";function s(){}function r(e,t,i){this.fn=e,this.context=t,this.once=i||!1}function n(e,t,s,n,o){if("function"!=typeof s)throw new TypeError("The listener must be a function");var a=new r(s,n||e,o),c=i?i+t:t;return e._events[c]?e._events[c].fn?e._events[c]=[e._events[c],a]:e._events[c].push(a):(e._events[c]=a,e._eventsCount++),e}function o(e,t){0==--e._eventsCount?e._events=new s:delete e._events[t]}function a(){this._events=new s,this._eventsCount=0}Object.create&&(s.prototype=Object.create(null),(new s).__proto__||(i=!1)),a.prototype.eventNames=function(){var e,s,r=[];if(0===this._eventsCount)return r;for(s in e=this._events)t.call(e,s)&&r.push(i?s.slice(1):s);return Object.getOwnPropertySymbols?r.concat(Object.getOwnPropertySymbols(e)):r},a.prototype.listeners=function(e){var t=i?i+e:e,s=this._events[t];if(!s)return[];if(s.fn)return[s.fn];for(var r=0,n=s.length,o=new Array(n);r{"use strict";var s=i(60195);function r(e,t){for(var i in t)n(t,i)&&(e[i]=t[i])}function n(e,t){return Object.prototype.hasOwnProperty.call(e,t)}e.exports=function(e){s(e)||(e={});for(var t=arguments.length,i=1;i{"use strict";const t=(()=>{const e=0,t=1,i=2,s={},r={font:"Standard",fontPath:"./fonts"};function n(e,t,i){return e===t&&e!==i&&e}function o(e,t){let i="|/\\[]{}()<>";if("_"===e){if(-1!==i.indexOf(t))return t}else if("_"===t&&-1!==i.indexOf(e))return e;return!1}function a(e,t){let i="| /\\ [] {} () <>",s=i.indexOf(e),r=i.indexOf(t);if(-1!==s&&-1!==r&&s!==r&&1!==Math.abs(s-r)){const e=Math.max(s,r);return i.substring(e,e+1)}return!1}function c(e,t){let i="[] {} ()",s=i.indexOf(e),r=i.indexOf(t);return-1!==s&&-1!==r&&Math.abs(s-r)<=1&&"|"}function l(e,t){let i="/\\ \\/ ><",s=i.indexOf(e),r=i.indexOf(t);return-1!==s&&-1!==r&&r-s==1&&{0:"|",3:"Y",6:"X"}[s]}function p(e,t,i){return e===i&&t===i&&i}function A(e,t){return e===t&&e}function u(e,t){let i="|/\\[]{}()<>";if("_"===e){if(-1!==i.indexOf(t))return t}else if("_"===t&&-1!==i.indexOf(e))return e;return!1}function d(e,t){let i="| /\\ [] {} () <>",s=i.indexOf(e),r=i.indexOf(t);if(-1!==s&&-1!==r&&s!==r&&1!==Math.abs(s-r)){const e=Math.max(s,r);return i.substring(e,e+1)}return!1}function h(e,t){return("-"===e&&"_"===t||"_"===e&&"-"===t)&&"="}function m(e,t){return"|"===e&&"|"===t&&"|"}function g(e,t,i){return" "===t||""===t||t===i&&" "!==e?e:t}function f(s,r,n){if(n.fittingRules.vLayout===e)return"invalid";let o,a,c,l,p=Math.min(s.length,r.length),g=!1;if(0===p)return"invalid";for(o=0;on?C(t,r-n):n>r&&C(e,n-r),s=function(e,t,i){let s,r,n,o,a,c,l=e.length,p=e.length,A=(t.length,1);for(;A<=l;){for(s=e.slice(Math.max(0,p-A),p),r=t.slice(0,Math.min(l,A)),n=r.length,c="",o=0;o=l?A[r]:E(A[r],u[r],s),d.push(o);return a=t.slice(Math.min(i,l),l),[].concat(p,d,a)}(e,t,s,i)}function v(s,r,A){if(A.fittingRules.hLayout===e)return 0;let u,d,h,m,g,f=s.length,E=r.length,C=f,y=1,v=!1,I=!1;if(0===f)return 0;e:for(;y<=C;){const e=f-y;for(d=s.substring(e,e+y),h=r.substring(0,Math.min(y,E)),u=0;u=y?"":I.substring(r,r+Math.max(0,y-r)),B[u]=m+f+E}return B}function B(e){let t,i=[];for(t=0;t0&&s.whitespaceBreak&&(p={chars:[],overlap:g}),1===s.printDirection&&(t=t.split("").reverse().join("")),c=t.length,r=0;r0&&(s.whitespaceBreak?(d=b(p.chars.concat([{fig:n,overlap:g}]),f,s),h=b(C.concat([{fig:d,overlap:p.overlap}]),f,s),l=w(h)):(h=I(a,n,g,s),l=w(h)),l>=s.width&&r>0&&(s.whitespaceBreak?(a=b(C.slice(0,-1),f,s),C.length>1&&(E.push(a),a=B(f)),C=[]):(E.push(a),a=B(f)))),s.width>0&&s.whitespaceBreak&&(u&&r!==c-1||p.chars.push({fig:n,overlap:g}),u||r===c-1)){for(m=null;h=b(p.chars,f,s),l=w(h),l>=s.width;)m=Q(p.chars,f,s),p={chars:m.chars},E.push(m.outputFigText);l>0&&(m?C.push({fig:h,overlap:1}):C.push({fig:h,overlap:p.overlap})),u&&(C.push({fig:n,overlap:g}),a=B(f)),r===c-1&&(a=b(C,f,s)),p={chars:[],overlap:g};continue}a=I(a,n,g,s)}return w(a)>0&&E.push(a),!0!==s.showHardBlanks&&E.forEach((function(e){for(c=e.length,o=0;o{S.loadFont(s,(function(o,a){if(o)return n(o),void(i&&i(o));const c=k(s,D(a,t),e);r(c),i&&i(null,c)}))}))},S.textSync=function(e,t){let i="";e+="","string"==typeof t?(i=t,t={}):i=(t=t||{}).font||r.font;var s=D(S.loadFontSync(i),t);return k(i,s,e)},S.metadata=function(e,t){e+="",S.loadFont(e,(function(i,r){i?t(i):t(null,r,s[e].comment)}))},S.defaults=function(e){if("object"==typeof e&&null!==e)for(var t in e)e.hasOwnProperty(t)&&(r[t]=e[t]);return JSON.parse(JSON.stringify(r))},S.parseFont=function(r,n){n=n.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),s[r]={};var o=n.split("\n"),a=o.splice(0,1)[0].split(" "),c=s[r],l={};if(l.hardBlank=a[0].substr(5,1),l.height=parseInt(a[1],10),l.baseline=parseInt(a[2],10),l.maxLength=parseInt(a[3],10),l.oldLayout=parseInt(a[4],10),l.numCommentLines=parseInt(a[5],10),l.printDirection=a.length>=6?parseInt(a[6],10):0,l.fullLayout=a.length>=7?parseInt(a[7],10):null,l.codeTagCount=a.length>=8?parseInt(a[8],10):null,l.fittingRules=function(s,r){let n,o,a,c,l={},p=[[16384,"vLayout",i],[8192,"vLayout",t],[4096,"vRule5",!0],[2048,"vRule4",!0],[1024,"vRule3",!0],[512,"vRule2",!0],[256,"vRule1",!0],[128,"hLayout",i],[64,"hLayout",t],[32,"hRule6",!0],[16,"hRule5",!0],[8,"hRule4",!0],[4,"hRule3",!0],[2,"hRule2",!0],[1,"hRule1",!0]];for(n=null!==r?r:s,o=0,a=p.length;o=c[0]?(n-=c[0],l[c[1]]=void 0===l[c[1]]?c[2]:l[c[1]]):"vLayout"!==c[1]&&"hLayout"!==c[1]&&(l[c[1]]=!1),o++;return void 0===l.hLayout?0===s?l.hLayout=t:-1===s?l.hLayout=e:l.hRule1||l.hRule2||l.hRule3||l.hRule4||l.hRule5||l.hRule6?l.hLayout=3:l.hLayout=i:l.hLayout===i&&(l.hRule1||l.hRule2||l.hRule3||l.hRule4||l.hRule5||l.hRule6)&&(l.hLayout=3),void 0===l.vLayout?l.vRule1||l.vRule2||l.vRule3||l.vRule4||l.vRule5?l.vLayout=3:l.vLayout=e:l.vLayout===i&&(l.vRule1||l.vRule2||l.vRule3||l.vRule4||l.vRule5)&&(l.vLayout=3),l}(l.oldLayout,l.fullLayout),c.options=l,1!==l.hardBlank.length||isNaN(l.height)||isNaN(l.baseline)||isNaN(l.maxLength)||isNaN(l.oldLayout)||isNaN(l.numCommentLines))throw new Error("FIGlet header contains invalid values.");let p,A=[];for(p=32;p<=126;p++)A.push(p);if(A=A.concat(196,214,220,228,246,252,223),o.length0&&c.numChars0;){if(u=o.splice(0,1)[0].split(" ")[0],/^0[xX][0-9a-fA-F]+$/.test(u))u=parseInt(u,16);else if(/^0[0-7]+$/.test(u))u=parseInt(u,8);else if(/^[0-9]+$/.test(u))u=parseInt(u,10);else{if(!/^-0[xX][0-9a-fA-F]+$/.test(u)){if(""===u)break;console.log("Invalid data:"+u),h=!0;break}u=parseInt(u,16)}for(c[u]=o.splice(0,l.height),p=0;pe.text())).then((function(e){i.push(e)}))}))}),Promise.resolve()).then((function(s){for(var r in e)e.hasOwnProperty(r)&&S.parseFont(e[r],i[r]);t&&t()}))},S.figFonts=s,S})();void 0!==e.exports&&(e.exports=t)},47707:(e,t,i)=>{const s=i(88042),r=i(57147),n=i(71017),o=n.join(__dirname,"/../fonts/");s.loadFont=function(e,t){s.figFonts[e]?t(null,s.figFonts[e].options):r.readFile(n.join(o,e+".flf"),{encoding:"utf-8"},(function(i,r){if(i)return t(i);r+="";try{t(null,s.parseFont(e,r))}catch(e){t(e)}}))},s.loadFontSync=function(e){if(s.figFonts[e])return s.figFonts[e].options;var t=r.readFileSync(n.join(o,e+".flf"),{encoding:"utf-8"});return t+="",s.parseFont(e,t)},s.fonts=function(e){var t=[];r.readdir(o,(function(i,s){if(i)return e(i);s.forEach((function(e){/\.flf$/.test(e)&&t.push(e.replace(/\.flf$/,""))})),e(null,t)}))},s.fontsSync=function(){var e=[];return r.readdirSync(o).forEach((function(t){/\.flf$/.test(t)&&e.push(t.replace(/\.flf$/,""))})),e},e.exports=s},12937:(e,t,i)=>{var s;e.exports=function(){if(!s){try{s=i(8856)("follow-redirects")}catch(e){}"function"!=typeof s&&(s=function(){})}s.apply(null,arguments)}},12564:(e,t,i)=>{var s=i(57310),r=s.URL,n=i(13685),o=i(95687),a=i(12781).Writable,c=i(39491),l=i(12937),p=["abort","aborted","connect","error","socket","timeout"],A=Object.create(null);p.forEach((function(e){A[e]=function(t,i,s){this._redirectable.emit(e,t,i,s)}}));var u=v("ERR_FR_REDIRECTION_FAILURE","Redirected request failed"),d=v("ERR_FR_TOO_MANY_REDIRECTS","Maximum number of redirects exceeded"),h=v("ERR_FR_MAX_BODY_LENGTH_EXCEEDED","Request body larger than maxBodyLength limit"),m=v("ERR_STREAM_WRITE_AFTER_END","write after end");function g(e,t){a.call(this),this._sanitizeOptions(e),this._options=e,this._ended=!1,this._ending=!1,this._redirectCount=0,this._redirects=[],this._requestBodyLength=0,this._requestBodyBuffers=[],t&&this.on("response",t);var i=this;this._onNativeResponse=function(e){i._processResponse(e)},this._performRequest()}function f(e){var t={maxRedirects:21,maxBodyLength:10485760},i={};return Object.keys(e).forEach((function(n){var o=n+":",a=i[o]=e[n],p=t[n]=Object.create(a);Object.defineProperties(p,{request:{value:function(e,n,a){if("string"==typeof e){var p=e;try{e=C(new r(p))}catch(t){e=s.parse(p)}}else r&&e instanceof r?e=C(e):(a=n,n=e,e={protocol:o});return"function"==typeof n&&(a=n,n=null),(n=Object.assign({maxRedirects:t.maxRedirects,maxBodyLength:t.maxBodyLength},e,n)).nativeProtocols=i,c.equal(n.protocol,o,"protocol mismatch"),l("options",n),new g(n,a)},configurable:!0,enumerable:!0,writable:!0},get:{value:function(e,t,i){var s=p.request(e,t,i);return s.end(),s},configurable:!0,enumerable:!0,writable:!0}})})),t}function E(){}function C(e){var t={protocol:e.protocol,hostname:e.hostname.startsWith("[")?e.hostname.slice(1,-1):e.hostname,hash:e.hash,search:e.search,pathname:e.pathname,path:e.pathname+e.search,href:e.href};return""!==e.port&&(t.port=Number(e.port)),t}function y(e,t){var i;for(var s in t)e.test(s)&&(i=t[s],delete t[s]);return null==i?void 0:String(i).trim()}function v(e,t){function i(e){Error.captureStackTrace(this,this.constructor),e?(this.message=t+": "+e.message,this.cause=e):this.message=t}return i.prototype=new Error,i.prototype.constructor=i,i.prototype.name="Error ["+e+"]",i.prototype.code=e,i}function I(e){for(var t of p)e.removeListener(t,A[t]);e.on("error",E),e.abort()}g.prototype=Object.create(a.prototype),g.prototype.abort=function(){I(this._currentRequest),this.emit("abort")},g.prototype.write=function(e,t,i){if(this._ending)throw new m;if(!("string"==typeof e||"object"==typeof e&&"length"in e))throw new TypeError("data should be a string, Buffer or Uint8Array");"function"==typeof t&&(i=t,t=null),0!==e.length?this._requestBodyLength+e.length<=this._options.maxBodyLength?(this._requestBodyLength+=e.length,this._requestBodyBuffers.push({data:e,encoding:t}),this._currentRequest.write(e,t,i)):(this.emit("error",new h),this.abort()):i&&i()},g.prototype.end=function(e,t,i){if("function"==typeof e?(i=e,e=t=null):"function"==typeof t&&(i=t,t=null),e){var s=this,r=this._currentRequest;this.write(e,t,(function(){s._ended=!0,r.end(null,null,i)})),this._ending=!0}else this._ended=this._ending=!0,this._currentRequest.end(null,null,i)},g.prototype.setHeader=function(e,t){this._options.headers[e]=t,this._currentRequest.setHeader(e,t)},g.prototype.removeHeader=function(e){delete this._options.headers[e],this._currentRequest.removeHeader(e)},g.prototype.setTimeout=function(e,t){var i=this;function s(t){t.setTimeout(e),t.removeListener("timeout",t.destroy),t.addListener("timeout",t.destroy)}function r(t){i._timeout&&clearTimeout(i._timeout),i._timeout=setTimeout((function(){i.emit("timeout"),n()}),e),s(t)}function n(){i._timeout&&(clearTimeout(i._timeout),i._timeout=null),i.removeListener("abort",n),i.removeListener("error",n),i.removeListener("response",n),t&&i.removeListener("timeout",t),i.socket||i._currentRequest.removeListener("socket",r)}return t&&this.on("timeout",t),this.socket?r(this.socket):this._currentRequest.once("socket",r),this.on("socket",s),this.on("abort",n),this.on("error",n),this.on("response",n),this},["flushHeaders","getHeader","setNoDelay","setSocketKeepAlive"].forEach((function(e){g.prototype[e]=function(t,i){return this._currentRequest[e](t,i)}})),["aborted","connection","socket"].forEach((function(e){Object.defineProperty(g.prototype,e,{get:function(){return this._currentRequest[e]}})})),g.prototype._sanitizeOptions=function(e){if(e.headers||(e.headers={}),e.host&&(e.hostname||(e.hostname=e.host),delete e.host),!e.pathname&&e.path){var t=e.path.indexOf("?");t<0?e.pathname=e.path:(e.pathname=e.path.substring(0,t),e.search=e.path.substring(t))}},g.prototype._performRequest=function(){var e=this._options.protocol,t=this._options.nativeProtocols[e];if(t){if(this._options.agents){var i=e.slice(0,-1);this._options.agent=this._options.agents[i]}var r=this._currentRequest=t.request(this._options,this._onNativeResponse);for(var n of(r._redirectable=this,p))r.on(n,A[n]);if(this._currentUrl=/^\//.test(this._options.path)?s.format(this._options):this._currentUrl=this._options.path,this._isRedirect){var o=0,a=this,c=this._requestBodyBuffers;!function e(t){if(r===a._currentRequest)if(t)a.emit("error",t);else if(o=400)return e.responseUrl=this._currentUrl,e.redirects=this._redirects,this.emit("response",e),void(this._requestBodyBuffers=[]);if(I(this._currentRequest),e.destroy(),++this._redirectCount>this._options.maxRedirects)this.emit("error",new d);else{var r,n=this._options.beforeRedirect;n&&(r=Object.assign({Host:e.req.getHeader("host")},this._options.headers));var o=this._options.method;((301===t||302===t)&&"POST"===this._options.method||303===t&&!/^(?:GET|HEAD)$/.test(this._options.method))&&(this._options.method="GET",this._requestBodyBuffers=[],y(/^content-/i,this._options.headers));var a,c=y(/^host$/i,this._options.headers),p=s.parse(this._currentUrl),A=c||p.host,h=/^\w+:/.test(i)?this._currentUrl:s.format(Object.assign(p,{host:A}));try{a=s.resolve(h,i)}catch(e){return void this.emit("error",new u(e))}l("redirecting to",a),this._isRedirect=!0;var m=s.parse(a);if(Object.assign(this._options,m),(m.protocol!==p.protocol&&"https:"!==m.protocol||m.host!==A&&!function(e,t){const i=e.length-t.length-1;return i>0&&"."===e[i]&&e.endsWith(t)}(m.host,A))&&y(/^(?:authorization|cookie)$/i,this._options.headers),"function"==typeof n){var g={headers:e.headers,statusCode:t},f={url:h,method:o,headers:r};try{n(this._options,g,f)}catch(e){return void this.emit("error",e)}this._sanitizeOptions(this._options)}try{this._performRequest()}catch(e){this.emit("error",new u(e))}}},e.exports=f({http:n,https:o}),e.exports.wrap=f},90504:(e,t,i)=>{var s=i(14598),r=i(73837),n=i(71017),o=i(13685),a=i(95687),c=i(57310).parse,l=i(57147),p=i(69335),A=i(62720),u=i(91117);function d(e){if(!(this instanceof d))return new d;for(var t in this._overheadLength=0,this._valueLength=0,this._valuesToMeasure=[],s.call(this),e=e||{})this[t]=e[t]}e.exports=d,r.inherits(d,s),d.LINE_BREAK="\r\n",d.DEFAULT_CONTENT_TYPE="application/octet-stream",d.prototype.append=function(e,t,i){"string"==typeof(i=i||{})&&(i={filename:i});var n=s.prototype.append.bind(this);if("number"==typeof t&&(t=""+t),r.isArray(t))this._error(new Error("Arrays are not supported."));else{var o=this._multiPartHeader(e,t,i),a=this._multiPartFooter();n(o),n(t),n(a),this._trackLength(o,t,i)}},d.prototype._trackLength=function(e,t,i){var s=0;null!=i.knownLength?s+=+i.knownLength:Buffer.isBuffer(t)?s=t.length:"string"==typeof t&&(s=Buffer.byteLength(t)),this._valueLength+=s,this._overheadLength+=Buffer.byteLength(e)+d.LINE_BREAK.length,t&&(t.path||t.readable&&t.hasOwnProperty("httpVersion"))&&(i.knownLength||this._valuesToMeasure.push(t))},d.prototype._lengthRetriever=function(e,t){e.hasOwnProperty("fd")?null!=e.end&&e.end!=1/0&&null!=e.start?t(null,e.end+1-(e.start?e.start:0)):l.stat(e.path,(function(i,s){var r;i?t(i):(r=s.size-(e.start?e.start:0),t(null,r))})):e.hasOwnProperty("httpVersion")?t(null,+e.headers["content-length"]):e.hasOwnProperty("httpModule")?(e.on("response",(function(i){e.pause(),t(null,+i.headers["content-length"])})),e.resume()):t("Unknown stream")},d.prototype._multiPartHeader=function(e,t,i){if("string"==typeof i.header)return i.header;var s,r=this._getContentDisposition(t,i),n=this._getContentType(t,i),o="",a={"Content-Disposition":["form-data",'name="'+e+'"'].concat(r||[]),"Content-Type":[].concat(n||[])};for(var c in"object"==typeof i.header&&u(a,i.header),a)a.hasOwnProperty(c)&&null!=(s=a[c])&&(Array.isArray(s)||(s=[s]),s.length&&(o+=c+": "+s.join("; ")+d.LINE_BREAK));return"--"+this.getBoundary()+d.LINE_BREAK+o+d.LINE_BREAK},d.prototype._getContentDisposition=function(e,t){var i,s;return"string"==typeof t.filepath?i=n.normalize(t.filepath).replace(/\\/g,"/"):t.filename||e.name||e.path?i=n.basename(t.filename||e.name||e.path):e.readable&&e.hasOwnProperty("httpVersion")&&(i=n.basename(e.client._httpMessage.path||"")),i&&(s='filename="'+i+'"'),s},d.prototype._getContentType=function(e,t){var i=t.contentType;return!i&&e.name&&(i=p.lookup(e.name)),!i&&e.path&&(i=p.lookup(e.path)),!i&&e.readable&&e.hasOwnProperty("httpVersion")&&(i=e.headers["content-type"]),i||!t.filepath&&!t.filename||(i=p.lookup(t.filepath||t.filename)),i||"object"!=typeof e||(i=d.DEFAULT_CONTENT_TYPE),i},d.prototype._multiPartFooter=function(){return function(e){var t=d.LINE_BREAK;0===this._streams.length&&(t+=this._lastBoundary()),e(t)}.bind(this)},d.prototype._lastBoundary=function(){return"--"+this.getBoundary()+"--"+d.LINE_BREAK},d.prototype.getHeaders=function(e){var t,i={"content-type":"multipart/form-data; boundary="+this.getBoundary()};for(t in e)e.hasOwnProperty(t)&&(i[t.toLowerCase()]=e[t]);return i},d.prototype.getBoundary=function(){return this._boundary||this._generateBoundary(),this._boundary},d.prototype.getBuffer=function(){for(var e=new Buffer.alloc(0),t=this.getBoundary(),i=0,s=this._streams.length;i{e.exports=function(e,t){return Object.keys(t).forEach((function(i){e[i]=e[i]||t[i]})),e}},87534:(e,t,i)=>{var s=i(14598),r=i(73837),n=i(71017),o=i(13685),a=i(95687),c=i(57310).parse,l=i(57147),p=i(12781).Stream,A=i(69335),u=i(62720),d=i(39049);function h(e){if(!(this instanceof h))return new h(e);for(var t in this._overheadLength=0,this._valueLength=0,this._valuesToMeasure=[],s.call(this),e=e||{})this[t]=e[t]}e.exports=h,r.inherits(h,s),h.LINE_BREAK="\r\n",h.DEFAULT_CONTENT_TYPE="application/octet-stream",h.prototype.append=function(e,t,i){"string"==typeof(i=i||{})&&(i={filename:i});var n=s.prototype.append.bind(this);if("number"==typeof t&&(t=""+t),r.isArray(t))this._error(new Error("Arrays are not supported."));else{var o=this._multiPartHeader(e,t,i),a=this._multiPartFooter();n(o),n(t),n(a),this._trackLength(o,t,i)}},h.prototype._trackLength=function(e,t,i){var s=0;null!=i.knownLength?s+=+i.knownLength:Buffer.isBuffer(t)?s=t.length:"string"==typeof t&&(s=Buffer.byteLength(t)),this._valueLength+=s,this._overheadLength+=Buffer.byteLength(e)+h.LINE_BREAK.length,t&&(t.path||t.readable&&t.hasOwnProperty("httpVersion")||t instanceof p)&&(i.knownLength||this._valuesToMeasure.push(t))},h.prototype._lengthRetriever=function(e,t){e.hasOwnProperty("fd")?null!=e.end&&e.end!=1/0&&null!=e.start?t(null,e.end+1-(e.start?e.start:0)):l.stat(e.path,(function(i,s){var r;i?t(i):(r=s.size-(e.start?e.start:0),t(null,r))})):e.hasOwnProperty("httpVersion")?t(null,+e.headers["content-length"]):e.hasOwnProperty("httpModule")?(e.on("response",(function(i){e.pause(),t(null,+i.headers["content-length"])})),e.resume()):t("Unknown stream")},h.prototype._multiPartHeader=function(e,t,i){if("string"==typeof i.header)return i.header;var s,r=this._getContentDisposition(t,i),n=this._getContentType(t,i),o="",a={"Content-Disposition":["form-data",'name="'+e+'"'].concat(r||[]),"Content-Type":[].concat(n||[])};for(var c in"object"==typeof i.header&&d(a,i.header),a)a.hasOwnProperty(c)&&null!=(s=a[c])&&(Array.isArray(s)||(s=[s]),s.length&&(o+=c+": "+s.join("; ")+h.LINE_BREAK));return"--"+this.getBoundary()+h.LINE_BREAK+o+h.LINE_BREAK},h.prototype._getContentDisposition=function(e,t){var i,s;return"string"==typeof t.filepath?i=n.normalize(t.filepath).replace(/\\/g,"/"):t.filename||e.name||e.path?i=n.basename(t.filename||e.name||e.path):e.readable&&e.hasOwnProperty("httpVersion")&&(i=n.basename(e.client._httpMessage.path||"")),i&&(s='filename="'+i+'"'),s},h.prototype._getContentType=function(e,t){var i=t.contentType;return!i&&e.name&&(i=A.lookup(e.name)),!i&&e.path&&(i=A.lookup(e.path)),!i&&e.readable&&e.hasOwnProperty("httpVersion")&&(i=e.headers["content-type"]),i||!t.filepath&&!t.filename||(i=A.lookup(t.filepath||t.filename)),i||"object"!=typeof e||(i=h.DEFAULT_CONTENT_TYPE),i},h.prototype._multiPartFooter=function(){return function(e){var t=h.LINE_BREAK;0===this._streams.length&&(t+=this._lastBoundary()),e(t)}.bind(this)},h.prototype._lastBoundary=function(){return"--"+this.getBoundary()+"--"+h.LINE_BREAK},h.prototype.getHeaders=function(e){var t,i={"content-type":"multipart/form-data; boundary="+this.getBoundary()};for(t in e)e.hasOwnProperty(t)&&(i[t.toLowerCase()]=e[t]);return i},h.prototype.setBoundary=function(e){this._boundary=e},h.prototype.getBoundary=function(){return this._boundary||this._generateBoundary(),this._boundary},h.prototype.getBuffer=function(){for(var e=new Buffer.alloc(0),t=this.getBoundary(),i=0,s=this._streams.length;i{e.exports=function(e,t){return Object.keys(t).forEach((function(i){e[i]=e[i]||t[i]})),e}},38125:(e,t,i)=>{"use strict";const s=i(57147),r=i(66577),n=i(62683),o=i(97537),a=i(56398),c=i(2237),l=i(68042),p=i(28418),A=i(38164);function u(e,t){if(""===e)return{data:{},content:e,excerpt:"",orig:e};let i=l(e);const s=u.cache[i.content];if(!t){if(s)return i=Object.assign({},s),i.orig=s.orig,i;u.cache[i.content]=i}return function(e,t){const i=n(t),s=i.delimiters[0],o="\n"+i.delimiters[1];let c=e.content;i.language&&(e.language=i.language);const l=s.length;if(!A.startsWith(c,s,l))return a(e,i),e;if(c.charAt(l)===s.slice(-1))return e;c=c.slice(l);const d=c.length,h=u.language(c,i);h.name&&(e.language=h.name,c=c.slice(h.raw.length));let m=c.indexOf(o);-1===m&&(m=d),e.matter=c.slice(0,m);return""===e.matter.replace(/^\s*#[^\n]+/gm,"").trim()?(e.isEmpty=!0,e.empty=e.content,e.data={}):e.data=p(e.language,e.matter,i),m===d?e.content="":(e.content=c.slice(m+o.length),"\r"===e.content[0]&&(e.content=e.content.slice(1)),"\n"===e.content[0]&&(e.content=e.content.slice(1))),a(e,i),(!0===i.sections||"function"==typeof i.section)&&r(e,i.section),e}(i,t)}u.engines=c,u.stringify=function(e,t,i){return"string"==typeof e&&(e=u(e,i)),o(e,t,i)},u.read=function(e,t){const i=u(s.readFileSync(e,"utf8"),t);return i.path=e,i},u.test=function(e,t){return A.startsWith(e,n(t).delimiters[0])},u.language=function(e,t){const i=n(t).delimiters[0];u.test(e)&&(e=e.slice(i.length));const s=e.slice(0,e.search(/\r?\n/));return{raw:s,name:s?s.trim():""}},u.cache={},u.clearCache=function(){u.cache={}},e.exports=u},62683:(e,t,i)=>{"use strict";const s=i(2237),r=i(38164);e.exports=function(e){const t=Object.assign({},e);return t.delimiters=r.arrayify(t.delims||t.delimiters||"---"),1===t.delimiters.length&&t.delimiters.push(t.delimiters[0]),t.language=(t.language||t.lang||"yaml").toLowerCase(),t.engines=Object.assign({},s,t.parsers,t.engines),t}},21825:e=>{"use strict";e.exports=function(e,t){let i=t.engines[e]||t.engines[function(e){switch(e.toLowerCase()){case"js":case"javascript":return"javascript";case"coffee":case"coffeescript":case"cson":return"coffee";case"yaml":case"yml":return"yaml";default:return e}}(e)];if(void 0===i)throw new Error('gray-matter engine "'+e+'" is not registered');return"function"==typeof i&&(i={parse:i}),i}},2237:(module,exports,__webpack_require__)=>{"use strict";const yaml=__webpack_require__(43236),engines=exports=module.exports;engines.yaml={parse:yaml.safeLoad.bind(yaml),stringify:yaml.safeDump.bind(yaml)},engines.json={parse:JSON.parse.bind(JSON),stringify:function(e,t){const i=Object.assign({replacer:null,space:2},t);return JSON.stringify(e,i.replacer,i.space)}},engines.javascript={parse:function parse(str,options,wrap){try{return!1!==wrap&&(str="(function() {\nreturn "+str.trim()+";\n}());"),eval(str)||{}}catch(e){if(!1!==wrap&&/(unexpected|identifier)/i.test(e.message))return parse(str,options,!1);throw new SyntaxError(e)}},stringify:function(){throw new Error("stringifying JavaScript is not supported")}}},56398:(e,t,i)=>{"use strict";const s=i(62683);e.exports=function(e,t){const i=s(t);if(null==e.data&&(e.data={}),"function"==typeof i.excerpt)return i.excerpt(e,i);const r=e.data.excerpt_separator||i.excerpt_separator;if(null==r&&(!1===i.excerpt||null==i.excerpt))return e;const n="string"==typeof i.excerpt?i.excerpt:r||i.delimiters[0],o=e.content.indexOf(n);return-1!==o&&(e.excerpt=e.content.slice(0,o)),e}},28418:(e,t,i)=>{"use strict";const s=i(21825),r=i(62683);e.exports=function(e,t,i){const n=r(i),o=s(e,n);if("function"!=typeof o.parse)throw new TypeError('expected "'+e+'.parse" to be a function');return o.parse(t,n)}},97537:(e,t,i)=>{"use strict";const s=i(79049),r=i(21825),n=i(62683);function o(e){return"\n"!==e.slice(-1)?e+"\n":e}e.exports=function(e,t,i){if(null==t&&null==i)switch(s(e)){case"object":t=e.data,i={};break;case"string":return e;default:throw new TypeError("expected file to be a string or object")}const a=e.content,c=n(i);if(null==t){if(!c.data)return e;t=c.data}const l=e.language||c.language,p=r(l,c);if("function"!=typeof p.stringify)throw new TypeError('expected "'+l+'.stringify" to be a function');t=Object.assign({},e.data,t);const A=c.delimiters[0],u=c.delimiters[1],d=p.stringify(t,i).trim();let h="";return"{}"!==d&&(h=o(A)+o(d)+o(u)),"string"==typeof e.excerpt&&""!==e.excerpt&&-1===a.indexOf(e.excerpt.trim())&&(h+=o(e.excerpt)+o(u)),h+o(a)}},68042:(e,t,i)=>{"use strict";const s=i(79049),r=i(97537),n=i(38164);e.exports=function(e){return"object"!==s(e)&&(e={content:e}),"object"!==s(e.data)&&(e.data={}),e.contents&&null==e.content&&(e.content=e.contents),n.define(e,"orig",n.toBuffer(e.content)),n.define(e,"language",e.language||""),n.define(e,"matter",e.matter||""),n.define(e,"stringify",(function(t,i){return i&&i.language&&(e.language=i.language),r(e,t,i)})),e.content=n.toString(e.content),e.isEmpty=!1,e.excerpt="",e}},38164:(e,t,i)=>{"use strict";const s=i(47494),r=i(79049);t.define=function(e,t,i){Reflect.defineProperty(e,t,{enumerable:!1,configurable:!0,writable:!0,value:i})},t.isBuffer=function(e){return"buffer"===r(e)},t.isObject=function(e){return"object"===r(e)},t.toBuffer=function(e){return"string"==typeof e?Buffer.from(e):e},t.toString=function(e){if(t.isBuffer(e))return s(String(e));if("string"!=typeof e)throw new TypeError("expected input to be a string or buffer");return s(e)},t.arrayify=function(e){return e?Array.isArray(e)?e:[e]:[]},t.startsWith=function(e,t,i){return"number"!=typeof i&&(i=t.length),e.slice(0,i)===t}},5506:e=>{"use strict";e.exports=(e,t=process.argv)=>{const i=e.startsWith("-")?"":1===e.length?"-":"--",s=t.indexOf(i+e),r=t.indexOf("--");return-1!==s&&(-1===r||s{"use strict";e.exports=(e,t=1,i)=>{if(i={indent:" ",includeEmptyLines:!1,...i},"string"!=typeof e)throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof e}\``);if("number"!=typeof t)throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof t}\``);if("string"!=typeof i.indent)throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof i.indent}\``);if(0===t)return e;const s=i.includeEmptyLines?/^/gm:/^(?!\s*$)/gm;return e.replace(s,i.indent.repeat(t))}},44236:(e,t,i)=>{try{var s=i(73837);if("function"!=typeof s.inherits)throw"";e.exports=s.inherits}catch(t){e.exports=i(67483)}},67483:e=>{"function"==typeof Object.create?e.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(e,t){if(t){e.super_=t;var i=function(){};i.prototype=t.prototype,e.prototype=new i,e.prototype.constructor=e}}},30547:e=>{e.exports=function(){return"undefined"!=typeof window&&"object"==typeof window.process&&"renderer"===window.process.type||!("undefined"==typeof process||"object"!=typeof process.versions||!process.versions.electron)||"object"==typeof navigator&&"string"==typeof navigator.userAgent&&navigator.userAgent.indexOf("Electron")>=0}},60195:e=>{"use strict";e.exports=function(e){return null!=e&&("object"==typeof e||"function"==typeof e)}},27759:e=>{"use strict";e.exports=({stream:e=process.stdout}={})=>Boolean(e&&e.isTTY&&"dumb"!==process.env.TERM&&!("CI"in process.env))},42412:e=>{"use strict";var t=e.exports=function(e){return null!==e&&"object"==typeof e&&"function"==typeof e.pipe};t.writable=function(e){return t(e)&&!1!==e.writable&&"function"==typeof e._write&&"object"==typeof e._writableState},t.readable=function(e){return t(e)&&!1!==e.readable&&"function"==typeof e._read&&"object"==typeof e._readableState},t.duplex=function(e){return t.writable(e)&&t.readable(e)},t.transform=function(e){return t.duplex(e)&&"function"==typeof e._transform&&"object"==typeof e._transformState}},5881:e=>{"use strict";e.exports=()=>"win32"!==process.platform||Boolean(process.env.CI)||Boolean(process.env.WT_SESSION)||"vscode"===process.env.TERM_PROGRAM||"xterm-256color"===process.env.TERM||"alacritty"===process.env.TERM},43236:(e,t,i)=>{"use strict";var s=i(5033);e.exports=s},5033:(e,t,i)=>{"use strict";var s=i(84780),r=i(44418);function n(e){return function(){throw new Error("Function "+e+" is deprecated and cannot be used.")}}e.exports.Type=i(42257),e.exports.Schema=i(38107),e.exports.FAILSAFE_SCHEMA=i(19777),e.exports.JSON_SCHEMA=i(93886),e.exports.CORE_SCHEMA=i(71514),e.exports.DEFAULT_SAFE_SCHEMA=i(79251),e.exports.DEFAULT_FULL_SCHEMA=i(13536),e.exports.load=s.load,e.exports.loadAll=s.loadAll,e.exports.safeLoad=s.safeLoad,e.exports.safeLoadAll=s.safeLoadAll,e.exports.dump=r.dump,e.exports.safeDump=r.safeDump,e.exports.YAMLException=i(86822),e.exports.MINIMAL_SCHEMA=i(19777),e.exports.SAFE_SCHEMA=i(79251),e.exports.DEFAULT_SCHEMA=i(13536),e.exports.scan=n("scan"),e.exports.parse=n("parse"),e.exports.compose=n("compose"),e.exports.addConstructor=n("addConstructor")},90560:e=>{"use strict";function t(e){return null==e}e.exports.isNothing=t,e.exports.isObject=function(e){return"object"==typeof e&&null!==e},e.exports.toArray=function(e){return Array.isArray(e)?e:t(e)?[]:[e]},e.exports.repeat=function(e,t){var i,s="";for(i=0;i{"use strict";var s=i(90560),r=i(86822),n=i(13536),o=i(79251),a=Object.prototype.toString,c=Object.prototype.hasOwnProperty,l=9,p=10,A=13,u=32,d=33,h=34,m=35,g=37,f=38,E=39,C=42,y=44,v=45,I=58,B=61,w=62,b=63,Q=64,x=91,k=93,D=96,S=123,_=124,R=125,T={0:"\\0",7:"\\a",8:"\\b",9:"\\t",10:"\\n",11:"\\v",12:"\\f",13:"\\r",27:"\\e",34:'\\"',92:"\\\\",133:"\\N",160:"\\_",8232:"\\L",8233:"\\P"},F=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"];function N(e){var t,i,n;if(t=e.toString(16).toUpperCase(),e<=255)i="x",n=2;else if(e<=65535)i="u",n=4;else{if(!(e<=4294967295))throw new r("code point within a string may not be greater than 0xFFFFFFFF");i="U",n=8}return"\\"+i+s.repeat("0",n-t.length)+t}function L(e){this.schema=e.schema||n,this.indent=Math.max(1,e.indent||2),this.noArrayIndent=e.noArrayIndent||!1,this.skipInvalid=e.skipInvalid||!1,this.flowLevel=s.isNothing(e.flowLevel)?-1:e.flowLevel,this.styleMap=function(e,t){var i,s,r,n,o,a,l;if(null===t)return{};for(i={},r=0,n=(s=Object.keys(t)).length;r-1&&i>=e.flowLevel;switch(function(e,t,i,s,r){var n,o,a,c,l=!1,A=!1,u=-1!==s,T=-1,F=P(c=e.charCodeAt(0))&&65279!==c&&!U(c)&&c!==v&&c!==b&&c!==I&&c!==y&&c!==x&&c!==k&&c!==S&&c!==R&&c!==m&&c!==f&&c!==C&&c!==d&&c!==_&&c!==B&&c!==w&&c!==E&&c!==h&&c!==g&&c!==Q&&c!==D&&!U(e.charCodeAt(e.length-1));if(t)for(n=0;n0?e.charCodeAt(n-1):null,F=F&&G(o,a)}else{for(n=0;ns&&" "!==e[T+1],T=n);else if(!P(o))return Y;a=n>0?e.charCodeAt(n-1):null,F=F&&G(o,a)}A=A||u&&n-T-1>s&&" "!==e[T+1]}return l||A?i>9&&V(e)?Y:A?q:J:F&&!r(e)?j:H}(t,a,e.indent,o,(function(t){return function(e,t){var i,s;for(i=0,s=e.implicitTypes.length;i"+z(t,e.indent)+$(O(function(e,t){for(var i,s,r,n=/(\n+)([^\n]*)/g,o=(r=-1!==(r=e.indexOf("\n"))?r:e.length,n.lastIndex=r,X(e.slice(0,r),t)),a="\n"===e[0]||" "===e[0];s=n.exec(e);){var c=s[1],l=s[2];i=" "===l[0],o+=c+(a||i||""===l?"":"\n")+X(l,t),a=i}return o}(t,o),n));case Y:return'"'+function(e){for(var t,i,s,r="",n=0;n=55296&&t<=56319&&(i=e.charCodeAt(n+1))>=56320&&i<=57343?(r+=N(1024*(t-55296)+i-56320+65536),n++):r+=!(s=T[t])&&P(t)?e[n]:s||N(t);return r}(t)+'"';default:throw new r("impossible error: invalid scalar style")}}()}function z(e,t){var i=V(e)?String(t):"",s="\n"===e[e.length-1];return i+(!s||"\n"!==e[e.length-2]&&"\n"!==e?s?"":"-":"+")+"\n"}function $(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function X(e,t){if(""===e||" "===e[0])return e;for(var i,s,r=/ [^ ]/g,n=0,o=0,a=0,c="";i=r.exec(e);)(a=i.index)-n>t&&(s=o>n?o:a,c+="\n"+e.slice(n,s),n=s+1),o=a;return c+="\n",e.length-n>t&&o>n?c+=e.slice(n,o)+"\n"+e.slice(o+1):c+=e.slice(n),c.slice(1)}function K(e,t,i){var s,n,o,l,p,A;for(o=0,l=(n=i?e.explicitTypes:e.implicitTypes).length;o tag resolver accepts not "'+A+'" style');s=p.represent[A](t,A)}e.dump=s}return!0}return!1}function Z(e,t,i,s,n,o){e.tag=null,e.dump=i,K(e,i,!1)||K(e,i,!0);var c=a.call(e.dump);s&&(s=e.flowLevel<0||e.flowLevel>t);var l,A,u="[object Object]"===c||"[object Array]"===c;if(u&&(A=-1!==(l=e.duplicates.indexOf(i))),(null!==e.tag&&"?"!==e.tag||A||2!==e.indent&&t>0)&&(n=!1),A&&e.usedDuplicates[l])e.dump="*ref_"+l;else{if(u&&A&&!e.usedDuplicates[l]&&(e.usedDuplicates[l]=!0),"[object Object]"===c)s&&0!==Object.keys(e.dump).length?(function(e,t,i,s){var n,o,a,c,l,A,u="",d=e.tag,h=Object.keys(i);if(!0===e.sortKeys)h.sort();else if("function"==typeof e.sortKeys)h.sort(e.sortKeys);else if(e.sortKeys)throw new r("sortKeys must be a boolean or a function");for(n=0,o=h.length;n1024)&&(e.dump&&p===e.dump.charCodeAt(0)?A+="?":A+="? "),A+=e.dump,l&&(A+=M(e,t)),Z(e,t+1,c,!0,l)&&(e.dump&&p===e.dump.charCodeAt(0)?A+=":":A+=": ",u+=A+=e.dump));e.tag=d,e.dump=u||"{}"}(e,t,e.dump,n),A&&(e.dump="&ref_"+l+e.dump)):(function(e,t,i){var s,r,n,o,a,c="",l=e.tag,p=Object.keys(i);for(s=0,r=p.length;s1024&&(a+="? "),a+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),Z(e,t,o,!1,!1)&&(c+=a+=e.dump));e.tag=l,e.dump="{"+c+"}"}(e,t,e.dump),A&&(e.dump="&ref_"+l+" "+e.dump));else if("[object Array]"===c){var d=e.noArrayIndent&&t>0?t-1:t;s&&0!==e.dump.length?(function(e,t,i,s){var r,n,o="",a=e.tag;for(r=0,n=i.length;r "+e.dump)}return!0}function ee(e,t){var i,s,r=[],n=[];for(te(e,r,n),i=0,s=n.length;i{"use strict";function t(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t},e.exports=t},84780:(e,t,i)=>{"use strict";var s=i(90560),r=i(86822),n=i(20917),o=i(79251),a=i(13536),c=Object.prototype.hasOwnProperty,l=1,p=2,A=3,u=4,d=1,h=2,m=3,g=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,f=/[\x85\u2028\u2029]/,E=/[,\[\]\{\}]/,C=/^(?:!|!!|![a-z\-]+!)$/i,y=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function v(e){return Object.prototype.toString.call(e)}function I(e){return 10===e||13===e}function B(e){return 9===e||32===e}function w(e){return 9===e||32===e||10===e||13===e}function b(e){return 44===e||91===e||93===e||123===e||125===e}function Q(e){var t;return 48<=e&&e<=57?e-48:97<=(t=32|e)&&t<=102?t-97+10:-1}function x(e){return 48===e?"\0":97===e?"":98===e?"\b":116===e||9===e?"\t":110===e?"\n":118===e?"\v":102===e?"\f":114===e?"\r":101===e?"":32===e?" ":34===e?'"':47===e?"/":92===e?"\\":78===e?"…":95===e?" ":76===e?"\u2028":80===e?"\u2029":""}function k(e){return e<=65535?String.fromCharCode(e):String.fromCharCode(55296+(e-65536>>10),56320+(e-65536&1023))}for(var D=new Array(256),S=new Array(256),_=0;_<256;_++)D[_]=x(_)?1:0,S[_]=x(_);function R(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||a,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function T(e,t){return new r(t,new n(e.filename,e.input,e.position,e.line,e.position-e.lineStart))}function F(e,t){throw T(e,t)}function N(e,t){e.onWarning&&e.onWarning.call(null,T(e,t))}var L={YAML:function(e,t,i){var s,r,n;null!==e.version&&F(e,"duplication of %YAML directive"),1!==i.length&&F(e,"YAML directive accepts exactly one argument"),null===(s=/^([0-9]+)\.([0-9]+)$/.exec(i[0]))&&F(e,"ill-formed argument of the YAML directive"),r=parseInt(s[1],10),n=parseInt(s[2],10),1!==r&&F(e,"unacceptable YAML version of the document"),e.version=i[0],e.checkLineBreaks=n<2,1!==n&&2!==n&&N(e,"unsupported YAML version of the document")},TAG:function(e,t,i){var s,r;2!==i.length&&F(e,"TAG directive accepts exactly two arguments"),s=i[0],r=i[1],C.test(s)||F(e,"ill-formed tag handle (first argument) of the TAG directive"),c.call(e.tagMap,s)&&F(e,'there is a previously declared suffix for "'+s+'" tag handle'),y.test(r)||F(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[s]=r}};function O(e,t,i,s){var r,n,o,a;if(t1&&(e.result+=s.repeat("\n",t-1))}function H(e,t){var i,s,r=e.tag,n=e.anchor,o=[],a=!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=o),s=e.input.charCodeAt(e.position);0!==s&&45===s&&w(e.input.charCodeAt(e.position+1));)if(a=!0,e.position++,G(e,!0,-1)&&e.lineIndent<=t)o.push(null),s=e.input.charCodeAt(e.position);else if(i=e.line,Y(e,t,A,!1,!0),o.push(e.result),G(e,!0,-1),s=e.input.charCodeAt(e.position),(e.line===i||e.lineIndent>t)&&0!==s)F(e,"bad indentation of a sequence entry");else if(e.lineIndentt?x=1:e.lineIndent===t?x=0:e.lineIndentt?x=1:e.lineIndent===t?x=0:e.lineIndentt)&&(Y(e,t,u,!0,r)&&(f?m=e.result:g=e.result),f||(U(e,A,d,h,m,g,n,o),h=m=g=null),G(e,!0,-1),a=e.input.charCodeAt(e.position)),e.lineIndent>t&&0!==a)F(e,"bad indentation of a mapping entry");else if(e.lineIndent=0))break;0===n?F(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):p?F(e,"repeat of an indentation width identifier"):(A=t+n-1,p=!0)}if(B(o)){do{o=e.input.charCodeAt(++e.position)}while(B(o));if(35===o)do{o=e.input.charCodeAt(++e.position)}while(!I(o)&&0!==o)}for(;0!==o;){for(P(e),e.lineIndent=0,o=e.input.charCodeAt(e.position);(!p||e.lineIndentA&&(A=e.lineIndent),I(o))u++;else{if(e.lineIndent0){for(r=o,n=0;r>0;r--)(o=Q(a=e.input.charCodeAt(++e.position)))>=0?n=(n<<4)+o:F(e,"expected hexadecimal character");e.result+=k(n),e.position++}else F(e,"unknown escape sequence");i=s=e.position}else I(a)?(O(e,i,s,!0),j(e,G(e,!1,t)),i=s=e.position):e.position===e.lineStart&&V(e)?F(e,"unexpected end of the document within a double quoted scalar"):(e.position++,s=e.position)}F(e,"unexpected end of the stream within a double quoted scalar")}(e,y)?R=!0:function(e){var t,i,s;if(42!==(s=e.input.charCodeAt(e.position)))return!1;for(s=e.input.charCodeAt(++e.position),t=e.position;0!==s&&!w(s)&&!b(s);)s=e.input.charCodeAt(++e.position);return e.position===t&&F(e,"name of an alias node must contain at least one character"),i=e.input.slice(t,e.position),c.call(e.anchorMap,i)||F(e,'unidentified alias "'+i+'"'),e.result=e.anchorMap[i],G(e,!0,-1),!0}(e)?(R=!0,null===e.tag&&null===e.anchor||F(e,"alias node should not have any properties")):function(e,t,i){var s,r,n,o,a,c,l,p,A=e.kind,u=e.result;if(w(p=e.input.charCodeAt(e.position))||b(p)||35===p||38===p||42===p||33===p||124===p||62===p||39===p||34===p||37===p||64===p||96===p)return!1;if((63===p||45===p)&&(w(s=e.input.charCodeAt(e.position+1))||i&&b(s)))return!1;for(e.kind="scalar",e.result="",r=n=e.position,o=!1;0!==p;){if(58===p){if(w(s=e.input.charCodeAt(e.position+1))||i&&b(s))break}else if(35===p){if(w(e.input.charCodeAt(e.position-1)))break}else{if(e.position===e.lineStart&&V(e)||i&&b(p))break;if(I(p)){if(a=e.line,c=e.lineStart,l=e.lineIndent,G(e,!1,-1),e.lineIndent>=t){o=!0,p=e.input.charCodeAt(e.position);continue}e.position=n,e.line=a,e.lineStart=c,e.lineIndent=l;break}}o&&(O(e,r,n,!1),j(e,e.line-a),r=n=e.position,o=!1),B(p)||(n=e.position+1),p=e.input.charCodeAt(++e.position)}return O(e,r,n,!1),!!e.result||(e.kind=A,e.result=u,!1)}(e,y,l===i)&&(R=!0,null===e.tag&&(e.tag="?")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===x&&(R=g&&H(e,v))),null!==e.tag&&"!"!==e.tag)if("?"===e.tag){for(null!==e.result&&"scalar"!==e.kind&&F(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"'),f=0,E=e.implicitTypes.length;f tag; it should be "'+C.kind+'", not "'+e.kind+'"'),C.resolve(e.result)?(e.result=C.construct(e.result),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):F(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")):F(e,"unknown tag !<"+e.tag+">");return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||R}function W(e){var t,i,s,r,n=e.position,o=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap={},e.anchorMap={};0!==(r=e.input.charCodeAt(e.position))&&(G(e,!0,-1),r=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==r));){for(o=!0,r=e.input.charCodeAt(++e.position),t=e.position;0!==r&&!w(r);)r=e.input.charCodeAt(++e.position);for(s=[],(i=e.input.slice(t,e.position)).length<1&&F(e,"directive name must not be less than one character in length");0!==r;){for(;B(r);)r=e.input.charCodeAt(++e.position);if(35===r){do{r=e.input.charCodeAt(++e.position)}while(0!==r&&!I(r));break}if(I(r))break;for(t=e.position;0!==r&&!w(r);)r=e.input.charCodeAt(++e.position);s.push(e.input.slice(t,e.position))}0!==r&&P(e),c.call(L,i)?L[i](e,i,s):N(e,'unknown document directive "'+i+'"')}G(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,G(e,!0,-1)):o&&F(e,"directives end mark is expected"),Y(e,e.lineIndent-1,u,!1,!0),G(e,!0,-1),e.checkLineBreaks&&f.test(e.input.slice(n,e.position))&&N(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&V(e)?46===e.input.charCodeAt(e.position)&&(e.position+=3,G(e,!0,-1)):e.position{"use strict";var s=i(90560);function r(e,t,i,s,r){this.name=e,this.buffer=t,this.position=i,this.line=s,this.column=r}r.prototype.getSnippet=function(e,t){var i,r,n,o,a;if(!this.buffer)return null;for(e=e||4,t=t||75,i="",r=this.position;r>0&&-1==="\0\r\n…\u2028\u2029".indexOf(this.buffer.charAt(r-1));)if(r-=1,this.position-r>t/2-1){i=" ... ",r+=5;break}for(n="",o=this.position;ot/2-1){n=" ... ",o-=5;break}return a=this.buffer.slice(r,o),s.repeat(" ",e)+i+a+n+"\n"+s.repeat(" ",e+this.position-r+i.length)+"^"},r.prototype.toString=function(e){var t,i="";return this.name&&(i+='in "'+this.name+'" '),i+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet())&&(i+=":\n"+t),i},e.exports=r},38107:(e,t,i)=>{"use strict";var s=i(90560),r=i(86822),n=i(42257);function o(e,t,i){var s=[];return e.include.forEach((function(e){i=o(e,t,i)})),e[t].forEach((function(e){i.forEach((function(t,i){t.tag===e.tag&&t.kind===e.kind&&s.push(i)})),i.push(e)})),i.filter((function(e,t){return-1===s.indexOf(t)}))}function a(e){this.include=e.include||[],this.implicit=e.implicit||[],this.explicit=e.explicit||[],this.implicit.forEach((function(e){if(e.loadKind&&"scalar"!==e.loadKind)throw new r("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.")})),this.compiledImplicit=o(this,"implicit",[]),this.compiledExplicit=o(this,"explicit",[]),this.compiledTypeMap=function(){var e,t,i={scalar:{},sequence:{},mapping:{},fallback:{}};function s(e){i[e.kind][e.tag]=i.fallback[e.tag]=e}for(e=0,t=arguments.length;e{"use strict";var s=i(38107);e.exports=new s({include:[i(93886)]})},13536:(e,t,i)=>{"use strict";var s=i(38107);e.exports=s.DEFAULT=new s({include:[i(79251)],explicit:[i(7021),i(55844),i(1327)]})},79251:(e,t,i)=>{"use strict";var s=i(38107);e.exports=new s({include:[i(71514)],implicit:[i(1363),i(3174)],explicit:[i(81676),i(53900),i(21908),i(30768)]})},19777:(e,t,i)=>{"use strict";var s=i(38107);e.exports=new s({explicit:[i(99678),i(23371),i(17261)]})},93886:(e,t,i)=>{"use strict";var s=i(38107);e.exports=new s({include:[i(19777)],implicit:[i(40707),i(47847),i(84302),i(28249)]})},42257:(e,t,i)=>{"use strict";var s=i(86822),r=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],n=["scalar","sequence","mapping"];e.exports=function(e,t){var i,o;if(t=t||{},Object.keys(t).forEach((function(t){if(-1===r.indexOf(t))throw new s('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.defaultStyle=t.defaultStyle||null,this.styleAliases=(i=t.styleAliases||null,o={},null!==i&&Object.keys(i).forEach((function(e){i[e].forEach((function(t){o[String(t)]=e}))})),o),-1===n.indexOf(this.kind))throw new s('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}},81676:(e,t,i)=>{"use strict";var s;try{s=i(14300).Buffer}catch(e){}var r=i(42257),n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";e.exports=new r("tag:yaml.org,2002:binary",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,i,s=0,r=e.length,o=n;for(i=0;i64)){if(t<0)return!1;s+=6}return s%8==0},construct:function(e){var t,i,r=e.replace(/[\r\n=]/g,""),o=r.length,a=n,c=0,l=[];for(t=0;t>16&255),l.push(c>>8&255),l.push(255&c)),c=c<<6|a.indexOf(r.charAt(t));return 0==(i=o%4*6)?(l.push(c>>16&255),l.push(c>>8&255),l.push(255&c)):18===i?(l.push(c>>10&255),l.push(c>>2&255)):12===i&&l.push(c>>4&255),s?s.from?s.from(l):new s(l):l},predicate:function(e){return s&&s.isBuffer(e)},represent:function(e){var t,i,s="",r=0,o=e.length,a=n;for(t=0;t>18&63],s+=a[r>>12&63],s+=a[r>>6&63],s+=a[63&r]),r=(r<<8)+e[t];return 0==(i=o%3)?(s+=a[r>>18&63],s+=a[r>>12&63],s+=a[r>>6&63],s+=a[63&r]):2===i?(s+=a[r>>10&63],s+=a[r>>4&63],s+=a[r<<2&63],s+=a[64]):1===i&&(s+=a[r>>2&63],s+=a[r<<4&63],s+=a[64],s+=a[64]),s}})},47847:(e,t,i)=>{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:bool",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t=e.length;return 4===t&&("true"===e||"True"===e||"TRUE"===e)||5===t&&("false"===e||"False"===e||"FALSE"===e)},construct:function(e){return"true"===e||"True"===e||"TRUE"===e},predicate:function(e){return"[object Boolean]"===Object.prototype.toString.call(e)},represent:{lowercase:function(e){return e?"true":"false"},uppercase:function(e){return e?"TRUE":"FALSE"},camelcase:function(e){return e?"True":"False"}},defaultStyle:"lowercase"})},28249:(e,t,i)=>{"use strict";var s=i(90560),r=i(42257),n=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),o=/^[-+]?[0-9]+e/;e.exports=new r("tag:yaml.org,2002:float",{kind:"scalar",resolve:function(e){return null!==e&&!(!n.test(e)||"_"===e[e.length-1])},construct:function(e){var t,i,s,r;return i="-"===(t=e.replace(/_/g,"").toLowerCase())[0]?-1:1,r=[],"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===i?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:t.indexOf(":")>=0?(t.split(":").forEach((function(e){r.unshift(parseFloat(e,10))})),t=0,s=1,r.forEach((function(e){t+=e*s,s*=60})),i*t):i*parseFloat(t,10)},predicate:function(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!=0||s.isNegativeZero(e))},represent:function(e,t){var i;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(s.isNegativeZero(e))return"-0.0";return i=e.toString(10),o.test(i)?i.replace("e",".e"):i},defaultStyle:"lowercase"})},84302:(e,t,i)=>{"use strict";var s=i(90560),r=i(42257);function n(e){return 48<=e&&e<=55}function o(e){return 48<=e&&e<=57}e.exports=new r("tag:yaml.org,2002:int",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,i,s=e.length,r=0,a=!1;if(!s)return!1;if("-"!==(t=e[r])&&"+"!==t||(t=e[++r]),"0"===t){if(r+1===s)return!0;if("b"===(t=e[++r])){for(r++;r=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0"+e.toString(8):"-0"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})},1327:(e,t,i)=>{"use strict";var s;try{s=i(87491)}catch(e){"undefined"!=typeof window&&(s=window.esprima)}var r=i(42257);e.exports=new r("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:function(e){if(null===e)return!1;try{var t="("+e+")",i=s.parse(t,{range:!0});return"Program"===i.type&&1===i.body.length&&"ExpressionStatement"===i.body[0].type&&("ArrowFunctionExpression"===i.body[0].expression.type||"FunctionExpression"===i.body[0].expression.type)}catch(e){return!1}},construct:function(e){var t,i="("+e+")",r=s.parse(i,{range:!0}),n=[];if("Program"!==r.type||1!==r.body.length||"ExpressionStatement"!==r.body[0].type||"ArrowFunctionExpression"!==r.body[0].expression.type&&"FunctionExpression"!==r.body[0].expression.type)throw new Error("Failed to resolve function");return r.body[0].expression.params.forEach((function(e){n.push(e.name)})),t=r.body[0].expression.body.range,"BlockStatement"===r.body[0].expression.body.type?new Function(n,i.slice(t[0]+1,t[1]-1)):new Function(n,"return "+i.slice(t[0],t[1]))},predicate:function(e){return"[object Function]"===Object.prototype.toString.call(e)},represent:function(e){return e.toString()}})},55844:(e,t,i)=>{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:function(e){if(null===e)return!1;if(0===e.length)return!1;var t=e,i=/\/([gim]*)$/.exec(e),s="";if("/"===t[0]){if(i&&(s=i[1]),s.length>3)return!1;if("/"!==t[t.length-s.length-1])return!1}return!0},construct:function(e){var t=e,i=/\/([gim]*)$/.exec(e),s="";return"/"===t[0]&&(i&&(s=i[1]),t=t.slice(1,t.length-s.length-1)),new RegExp(t,s)},predicate:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},represent:function(e){var t="/"+e.source+"/";return e.global&&(t+="g"),e.multiline&&(t+="m"),e.ignoreCase&&(t+="i"),t}})},7021:(e,t,i)=>{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:function(){return!0},construct:function(){},predicate:function(e){return void 0===e},represent:function(){return""}})},17261:(e,t,i)=>{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:map",{kind:"mapping",construct:function(e){return null!==e?e:{}}})},3174:(e,t,i)=>{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:merge",{kind:"scalar",resolve:function(e){return"<<"===e||null===e}})},40707:(e,t,i)=>{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:null",{kind:"scalar",resolve:function(e){if(null===e)return!0;var t=e.length;return 1===t&&"~"===e||4===t&&("null"===e||"Null"===e||"NULL"===e)},construct:function(){return null},predicate:function(e){return null===e},represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})},53900:(e,t,i)=>{"use strict";var s=i(42257),r=Object.prototype.hasOwnProperty,n=Object.prototype.toString;e.exports=new s("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,i,s,o,a,c=[],l=e;for(t=0,i=l.length;t{"use strict";var s=i(42257),r=Object.prototype.toString;e.exports=new s("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,i,s,n,o,a=e;for(o=new Array(a.length),t=0,i=a.length;t{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(e){return null!==e?e:[]}})},30768:(e,t,i)=>{"use strict";var s=i(42257),r=Object.prototype.hasOwnProperty;e.exports=new s("tag:yaml.org,2002:set",{kind:"mapping",resolve:function(e){if(null===e)return!0;var t,i=e;for(t in i)if(r.call(i,t)&&null!==i[t])return!1;return!0},construct:function(e){return null!==e?e:{}}})},99678:(e,t,i)=>{"use strict";var s=i(42257);e.exports=new s("tag:yaml.org,2002:str",{kind:"scalar",construct:function(e){return null!==e?e:""}})},1363:(e,t,i)=>{"use strict";var s=i(42257),r=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),n=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");e.exports=new s("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:function(e){return null!==e&&(null!==r.exec(e)||null!==n.exec(e))},construct:function(e){var t,i,s,o,a,c,l,p,A=0,u=null;if(null===(t=r.exec(e))&&(t=n.exec(e)),null===t)throw new Error("Date resolve error");if(i=+t[1],s=+t[2]-1,o=+t[3],!t[4])return new Date(Date.UTC(i,s,o));if(a=+t[4],c=+t[5],l=+t[6],t[7]){for(A=t[7].slice(0,3);A.length<3;)A+="0";A=+A}return t[9]&&(u=6e4*(60*+t[10]+ +(t[11]||0)),"-"===t[9]&&(u=-u)),p=new Date(Date.UTC(i,s,o,a,c,l,A)),u&&p.setTime(p.getTime()-u),p},instanceOf:Date,represent:function(e){return e.toISOString()}})},20097:(e,t,i)=>{"use strict";var s=i(37980),r=i(99719);function n(e,t){return function(){throw new Error("Function yaml."+e+" is removed in js-yaml 4. Use yaml."+t+" instead, which is now safe by default.")}}e.exports.Type=i(95344),e.exports.Schema=i(42459),e.exports.FAILSAFE_SCHEMA=i(69366),e.exports.JSON_SCHEMA=i(74068),e.exports.CORE_SCHEMA=i(75243),e.exports.DEFAULT_SCHEMA=i(66392),e.exports.load=s.load,e.exports.loadAll=s.loadAll,e.exports.dump=r.dump,e.exports.YAMLException=i(34699),e.exports.types={binary:i(3389),float:i(25948),map:i(69274),null:i(91237),pairs:i(97988),set:i(576),timestamp:i(26405),bool:i(93691),int:i(30492),merge:i(30945),omap:i(4868),seq:i(56821),str:i(43432)},e.exports.safeLoad=n("safeLoad","load"),e.exports.safeLoadAll=n("safeLoadAll","loadAll"),e.exports.safeDump=n("safeDump","dump")},11392:e=>{"use strict";function t(e){return null==e}e.exports.isNothing=t,e.exports.isObject=function(e){return"object"==typeof e&&null!==e},e.exports.toArray=function(e){return Array.isArray(e)?e:t(e)?[]:[e]},e.exports.repeat=function(e,t){var i,s="";for(i=0;i{"use strict";var s=i(11392),r=i(34699),n=i(66392),o=Object.prototype.toString,a=Object.prototype.hasOwnProperty,c=65279,l=9,p=10,A=13,u=32,d=33,h=34,m=35,g=37,f=38,E=39,C=42,y=44,v=45,I=58,B=61,w=62,b=63,Q=64,x=91,k=93,D=96,S=123,_=124,R=125,T={0:"\\0",7:"\\a",8:"\\b",9:"\\t",10:"\\n",11:"\\v",12:"\\f",13:"\\r",27:"\\e",34:'\\"',92:"\\\\",133:"\\N",160:"\\_",8232:"\\L",8233:"\\P"},F=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"],N=/^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/;function L(e){var t,i,n;if(t=e.toString(16).toUpperCase(),e<=255)i="x",n=2;else if(e<=65535)i="u",n=4;else{if(!(e<=4294967295))throw new r("code point within a string may not be greater than 0xFFFFFFFF");i="U",n=8}return"\\"+i+s.repeat("0",n-t.length)+t}var O=2;function M(e){this.schema=e.schema||n,this.indent=Math.max(1,e.indent||2),this.noArrayIndent=e.noArrayIndent||!1,this.skipInvalid=e.skipInvalid||!1,this.flowLevel=s.isNothing(e.flowLevel)?-1:e.flowLevel,this.styleMap=function(e,t){var i,s,r,n,o,c,l;if(null===t)return{};for(i={},r=0,n=(s=Object.keys(t)).length;r=55296&&s<=56319&&t+1=56320&&i<=57343?1024*(s-55296)+i-56320+65536:s}function q(e){return/^\n* /.test(e)}var Y=1,W=2,z=3,$=4,X=5;function K(e,t,i,s,n){e.dump=function(){if(0===t.length)return e.quotingType===O?'""':"''";if(!e.noCompatMode&&(-1!==F.indexOf(t)||N.test(t)))return e.quotingType===O?'"'+t+'"':"'"+t+"'";var o=e.indent*Math.max(1,i),a=-1===e.lineWidth?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-o),l=s||e.flowLevel>-1&&i>=e.flowLevel;switch(function(e,t,i,s,r,n,o,a){var l,A,u=0,T=null,F=!1,N=!1,L=-1!==s,M=-1,U=V(A=J(e,0))&&A!==c&&!G(A)&&A!==v&&A!==b&&A!==I&&A!==y&&A!==x&&A!==k&&A!==S&&A!==R&&A!==m&&A!==f&&A!==C&&A!==d&&A!==_&&A!==B&&A!==w&&A!==E&&A!==h&&A!==g&&A!==Q&&A!==D&&function(e){return!G(e)&&e!==I}(J(e,e.length-1));if(t||o)for(l=0;l=65536?l+=2:l++){if(!V(u=J(e,l)))return X;U=U&&H(u,T,a),T=u}else{for(l=0;l=65536?l+=2:l++){if((u=J(e,l))===p)F=!0,L&&(N=N||l-M-1>s&&" "!==e[M+1],M=l);else if(!V(u))return X;U=U&&H(u,T,a),T=u}N=N||L&&l-M-1>s&&" "!==e[M+1]}return F||N?i>9&&q(e)?X:o?n===O?X:W:N?$:z:!U||o||r(e)?n===O?X:W:Y}(t,l,e.indent,a,(function(t){return function(e,t){var i,s;for(i=0,s=e.implicitTypes.length;i"+Z(t,e.indent)+ee(U(function(e,t){for(var i,s,r,n=/(\n+)([^\n]*)/g,o=(r=-1!==(r=e.indexOf("\n"))?r:e.length,n.lastIndex=r,te(e.slice(0,r),t)),a="\n"===e[0]||" "===e[0];s=n.exec(e);){var c=s[1],l=s[2];i=" "===l[0],o+=c+(a||i||""===l?"":"\n")+te(l,t),a=i}return o}(t,a),o));case X:return'"'+function(e){for(var t,i="",s=0,r=0;r=65536?r+=2:r++)s=J(e,r),!(t=T[s])&&V(s)?(i+=e[r],s>=65536&&(i+=e[r+1])):i+=t||L(s);return i}(t)+'"';default:throw new r("impossible error: invalid scalar style")}}()}function Z(e,t){var i=q(e)?String(t):"",s="\n"===e[e.length-1];return i+(!s||"\n"!==e[e.length-2]&&"\n"!==e?s?"":"-":"+")+"\n"}function ee(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function te(e,t){if(""===e||" "===e[0])return e;for(var i,s,r=/ [^ ]/g,n=0,o=0,a=0,c="";i=r.exec(e);)(a=i.index)-n>t&&(s=o>n?o:a,c+="\n"+e.slice(n,s),n=s+1),o=a;return c+="\n",e.length-n>t&&o>n?c+=e.slice(n,o)+"\n"+e.slice(o+1):c+=e.slice(n),c.slice(1)}function ie(e,t,i,s){var r,n,o,a="",c=e.tag;for(r=0,n=i.length;r tag resolver accepts not "'+A+'" style');s=p.represent[A](t,A)}e.dump=s}return!0}return!1}function re(e,t,i,s,n,a,c){e.tag=null,e.dump=i,se(e,i,!1)||se(e,i,!0);var l,A=o.call(e.dump),u=s;s&&(s=e.flowLevel<0||e.flowLevel>t);var d,h,m="[object Object]"===A||"[object Array]"===A;if(m&&(h=-1!==(d=e.duplicates.indexOf(i))),(null!==e.tag&&"?"!==e.tag||h||2!==e.indent&&t>0)&&(n=!1),h&&e.usedDuplicates[d])e.dump="*ref_"+d;else{if(m&&h&&!e.usedDuplicates[d]&&(e.usedDuplicates[d]=!0),"[object Object]"===A)s&&0!==Object.keys(e.dump).length?(function(e,t,i,s){var n,o,a,c,l,A,u="",d=e.tag,h=Object.keys(i);if(!0===e.sortKeys)h.sort();else if("function"==typeof e.sortKeys)h.sort(e.sortKeys);else if(e.sortKeys)throw new r("sortKeys must be a boolean or a function");for(n=0,o=h.length;n1024)&&(e.dump&&p===e.dump.charCodeAt(0)?A+="?":A+="? "),A+=e.dump,l&&(A+=P(e,t)),re(e,t+1,c,!0,l)&&(e.dump&&p===e.dump.charCodeAt(0)?A+=":":A+=": ",u+=A+=e.dump));e.tag=d,e.dump=u||"{}"}(e,t,e.dump,n),h&&(e.dump="&ref_"+d+e.dump)):(function(e,t,i){var s,r,n,o,a,c="",l=e.tag,p=Object.keys(i);for(s=0,r=p.length;s1024&&(a+="? "),a+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),re(e,t,o,!1,!1)&&(c+=a+=e.dump));e.tag=l,e.dump="{"+c+"}"}(e,t,e.dump),h&&(e.dump="&ref_"+d+" "+e.dump));else if("[object Array]"===A)s&&0!==e.dump.length?(e.noArrayIndent&&!c&&t>0?ie(e,t-1,e.dump,n):ie(e,t,e.dump,n),h&&(e.dump="&ref_"+d+e.dump)):(function(e,t,i){var s,r,n,o="",a=e.tag;for(s=0,r=i.length;s",e.dump=l+" "+e.dump)}return!0}function ne(e,t){var i,s,r=[],n=[];for(oe(e,r,n),i=0,s=n.length;i{"use strict";function t(e,t){var i="",s=e.reason||"(unknown reason)";return e.mark?(e.mark.name&&(i+='in "'+e.mark.name+'" '),i+="("+(e.mark.line+1)+":"+(e.mark.column+1)+")",!t&&e.mark.snippet&&(i+="\n\n"+e.mark.snippet),s+" "+i):s}function i(e,i){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=i,this.message=t(this,!1),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}i.prototype=Object.create(Error.prototype),i.prototype.constructor=i,i.prototype.toString=function(e){return this.name+": "+t(this,e)},e.exports=i},37980:(e,t,i)=>{"use strict";var s=i(11392),r=i(34699),n=i(25638),o=i(66392),a=Object.prototype.hasOwnProperty,c=1,l=2,p=3,A=4,u=1,d=2,h=3,m=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,g=/[\x85\u2028\u2029]/,f=/[,\[\]\{\}]/,E=/^(?:!|!!|![a-z\-]+!)$/i,C=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function y(e){return Object.prototype.toString.call(e)}function v(e){return 10===e||13===e}function I(e){return 9===e||32===e}function B(e){return 9===e||32===e||10===e||13===e}function w(e){return 44===e||91===e||93===e||123===e||125===e}function b(e){var t;return 48<=e&&e<=57?e-48:97<=(t=32|e)&&t<=102?t-97+10:-1}function Q(e){return 48===e?"\0":97===e?"":98===e?"\b":116===e||9===e?"\t":110===e?"\n":118===e?"\v":102===e?"\f":114===e?"\r":101===e?"":32===e?" ":34===e?'"':47===e?"/":92===e?"\\":78===e?"…":95===e?" ":76===e?"\u2028":80===e?"\u2029":""}function x(e){return e<=65535?String.fromCharCode(e):String.fromCharCode(55296+(e-65536>>10),56320+(e-65536&1023))}for(var k=new Array(256),D=new Array(256),S=0;S<256;S++)k[S]=Q(S)?1:0,D[S]=Q(S);function _(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||o,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function R(e,t){var i={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return i.snippet=n(i),new r(t,i)}function T(e,t){throw R(e,t)}function F(e,t){e.onWarning&&e.onWarning.call(null,R(e,t))}var N={YAML:function(e,t,i){var s,r,n;null!==e.version&&T(e,"duplication of %YAML directive"),1!==i.length&&T(e,"YAML directive accepts exactly one argument"),null===(s=/^([0-9]+)\.([0-9]+)$/.exec(i[0]))&&T(e,"ill-formed argument of the YAML directive"),r=parseInt(s[1],10),n=parseInt(s[2],10),1!==r&&T(e,"unacceptable YAML version of the document"),e.version=i[0],e.checkLineBreaks=n<2,1!==n&&2!==n&&F(e,"unsupported YAML version of the document")},TAG:function(e,t,i){var s,r;2!==i.length&&T(e,"TAG directive accepts exactly two arguments"),s=i[0],r=i[1],E.test(s)||T(e,"ill-formed tag handle (first argument) of the TAG directive"),a.call(e.tagMap,s)&&T(e,'there is a previously declared suffix for "'+s+'" tag handle'),C.test(r)||T(e,"ill-formed tag prefix (second argument) of the TAG directive");try{r=decodeURIComponent(r)}catch(t){T(e,"tag prefix is malformed: "+r)}e.tagMap[s]=r}};function L(e,t,i,s){var r,n,o,a;if(t1&&(e.result+=s.repeat("\n",t-1))}function j(e,t){var i,s,r=e.tag,n=e.anchor,o=[],a=!1;if(-1!==e.firstTabInLine)return!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=o),s=e.input.charCodeAt(e.position);0!==s&&(-1!==e.firstTabInLine&&(e.position=e.firstTabInLine,T(e,"tab characters must not be used in indentation")),45===s)&&B(e.input.charCodeAt(e.position+1));)if(a=!0,e.position++,P(e,!0,-1)&&e.lineIndent<=t)o.push(null),s=e.input.charCodeAt(e.position);else if(i=e.line,q(e,t,p,!1,!0),o.push(e.result),P(e,!0,-1),s=e.input.charCodeAt(e.position),(e.line===i||e.lineIndent>t)&&0!==s)T(e,"bad indentation of a sequence entry");else if(e.lineIndentt?_=1:e.lineIndent===t?_=0:e.lineIndentt?_=1:e.lineIndent===t?_=0:e.lineIndentt)&&(C&&(o=e.line,a=e.lineStart,c=e.position),q(e,t,A,!0,r)&&(C?f=e.result:E=e.result),C||(M(e,h,m,g,f,E,o,a,c),g=f=E=null),P(e,!0,-1),p=e.input.charCodeAt(e.position)),(e.line===n||e.lineIndent>t)&&0!==p)T(e,"bad indentation of a mapping entry");else if(e.lineIndent=0))break;0===n?T(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):p?T(e,"repeat of an indentation width identifier"):(A=t+n-1,p=!0)}if(I(o)){do{o=e.input.charCodeAt(++e.position)}while(I(o));if(35===o)do{o=e.input.charCodeAt(++e.position)}while(!v(o)&&0!==o)}for(;0!==o;){for(U(e),e.lineIndent=0,o=e.input.charCodeAt(e.position);(!p||e.lineIndentA&&(A=e.lineIndent),v(o))m++;else{if(e.lineIndent0){for(r=o,n=0;r>0;r--)(o=b(a=e.input.charCodeAt(++e.position)))>=0?n=(n<<4)+o:T(e,"expected hexadecimal character");e.result+=x(n),e.position++}else T(e,"unknown escape sequence");i=s=e.position}else v(a)?(L(e,i,s,!0),V(e,P(e,!1,t)),i=s=e.position):e.position===e.lineStart&&G(e)?T(e,"unexpected end of the document within a double quoted scalar"):(e.position++,s=e.position)}T(e,"unexpected end of the stream within a double quoted scalar")}(e,Q)?F=!0:function(e){var t,i,s;if(42!==(s=e.input.charCodeAt(e.position)))return!1;for(s=e.input.charCodeAt(++e.position),t=e.position;0!==s&&!B(s)&&!w(s);)s=e.input.charCodeAt(++e.position);return e.position===t&&T(e,"name of an alias node must contain at least one character"),i=e.input.slice(t,e.position),a.call(e.anchorMap,i)||T(e,'unidentified alias "'+i+'"'),e.result=e.anchorMap[i],P(e,!0,-1),!0}(e)?(F=!0,null===e.tag&&null===e.anchor||T(e,"alias node should not have any properties")):function(e,t,i){var s,r,n,o,a,c,l,p,A=e.kind,u=e.result;if(B(p=e.input.charCodeAt(e.position))||w(p)||35===p||38===p||42===p||33===p||124===p||62===p||39===p||34===p||37===p||64===p||96===p)return!1;if((63===p||45===p)&&(B(s=e.input.charCodeAt(e.position+1))||i&&w(s)))return!1;for(e.kind="scalar",e.result="",r=n=e.position,o=!1;0!==p;){if(58===p){if(B(s=e.input.charCodeAt(e.position+1))||i&&w(s))break}else if(35===p){if(B(e.input.charCodeAt(e.position-1)))break}else{if(e.position===e.lineStart&&G(e)||i&&w(p))break;if(v(p)){if(a=e.line,c=e.lineStart,l=e.lineIndent,P(e,!1,-1),e.lineIndent>=t){o=!0,p=e.input.charCodeAt(e.position);continue}e.position=n,e.line=a,e.lineStart=c,e.lineIndent=l;break}}o&&(L(e,r,n,!1),V(e,e.line-a),r=n=e.position,o=!1),I(p)||(n=e.position+1),p=e.input.charCodeAt(++e.position)}return L(e,r,n,!1),!!e.result||(e.kind=A,e.result=u,!1)}(e,Q,c===i)&&(F=!0,null===e.tag&&(e.tag="?")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===_&&(F=g&&j(e,S))),null===e.tag)null!==e.anchor&&(e.anchorMap[e.anchor]=e.result);else if("?"===e.tag){for(null!==e.result&&"scalar"!==e.kind&&T(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"'),f=0,E=e.implicitTypes.length;f"),null!==e.result&&y.kind!==e.kind&&T(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+y.kind+'", not "'+e.kind+'"'),y.resolve(e.result,e.tag)?(e.result=y.construct(e.result,e.tag),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):T(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||F}function Y(e){var t,i,s,r,n=e.position,o=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);0!==(r=e.input.charCodeAt(e.position))&&(P(e,!0,-1),r=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==r));){for(o=!0,r=e.input.charCodeAt(++e.position),t=e.position;0!==r&&!B(r);)r=e.input.charCodeAt(++e.position);for(s=[],(i=e.input.slice(t,e.position)).length<1&&T(e,"directive name must not be less than one character in length");0!==r;){for(;I(r);)r=e.input.charCodeAt(++e.position);if(35===r){do{r=e.input.charCodeAt(++e.position)}while(0!==r&&!v(r));break}if(v(r))break;for(t=e.position;0!==r&&!B(r);)r=e.input.charCodeAt(++e.position);s.push(e.input.slice(t,e.position))}0!==r&&U(e),a.call(N,i)?N[i](e,i,s):F(e,'unknown document directive "'+i+'"')}P(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,P(e,!0,-1)):o&&T(e,"directives end mark is expected"),q(e,e.lineIndent-1,A,!1,!0),P(e,!0,-1),e.checkLineBreaks&&g.test(e.input.slice(n,e.position))&&F(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&G(e)?46===e.input.charCodeAt(e.position)&&(e.position+=3,P(e,!0,-1)):e.position{"use strict";var s=i(34699),r=i(95344);function n(e,t){var i=[];return e[t].forEach((function(e){var t=i.length;i.forEach((function(i,s){i.tag===e.tag&&i.kind===e.kind&&i.multi===e.multi&&(t=s)})),i[t]=e})),i}function o(e){return this.extend(e)}o.prototype.extend=function(e){var t=[],i=[];if(e instanceof r)i.push(e);else if(Array.isArray(e))i=i.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new s("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(i=i.concat(e.explicit))}t.forEach((function(e){if(!(e instanceof r))throw new s("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new s("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new s("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),i.forEach((function(e){if(!(e instanceof r))throw new s("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var a=Object.create(o.prototype);return a.implicit=(this.implicit||[]).concat(t),a.explicit=(this.explicit||[]).concat(i),a.compiledImplicit=n(a,"implicit"),a.compiledExplicit=n(a,"explicit"),a.compiledTypeMap=function(){var e,t,i={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function s(e){e.multi?(i.multi[e.kind].push(e),i.multi.fallback.push(e)):i[e.kind][e.tag]=i.fallback[e.tag]=e}for(e=0,t=arguments.length;e{"use strict";e.exports=i(74068)},66392:(e,t,i)=>{"use strict";e.exports=i(75243).extend({implicit:[i(26405),i(30945)],explicit:[i(3389),i(4868),i(97988),i(576)]})},69366:(e,t,i)=>{"use strict";var s=i(42459);e.exports=new s({explicit:[i(43432),i(56821),i(69274)]})},74068:(e,t,i)=>{"use strict";e.exports=i(69366).extend({implicit:[i(91237),i(93691),i(30492),i(25948)]})},25638:(e,t,i)=>{"use strict";var s=i(11392);function r(e,t,i,s,r){var n="",o="",a=Math.floor(r/2)-1;return s-t>a&&(t=s-a+(n=" ... ").length),i-s>a&&(i=s+a-(o=" ...").length),{str:n+e.slice(t,i).replace(/\t/g,"→")+o,pos:s-t+n.length}}function n(e,t){return s.repeat(" ",t-e.length)+e}e.exports=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var i,o=/\r?\n|\r|\0/g,a=[0],c=[],l=-1;i=o.exec(e.buffer);)c.push(i.index),a.push(i.index+i[0].length),e.position<=i.index&&l<0&&(l=a.length-2);l<0&&(l=a.length-1);var p,A,u="",d=Math.min(e.line+t.linesAfter,c.length).toString().length,h=t.maxLength-(t.indent+d+3);for(p=1;p<=t.linesBefore&&!(l-p<0);p++)A=r(e.buffer,a[l-p],c[l-p],e.position-(a[l]-a[l-p]),h),u=s.repeat(" ",t.indent)+n((e.line-p+1).toString(),d)+" | "+A.str+"\n"+u;for(A=r(e.buffer,a[l],c[l],e.position,h),u+=s.repeat(" ",t.indent)+n((e.line+1).toString(),d)+" | "+A.str+"\n",u+=s.repeat("-",t.indent+d+3+A.pos)+"^\n",p=1;p<=t.linesAfter&&!(l+p>=c.length);p++)A=r(e.buffer,a[l+p],c[l+p],e.position-(a[l]-a[l+p]),h),u+=s.repeat(" ",t.indent)+n((e.line+p+1).toString(),d)+" | "+A.str+"\n";return u.replace(/\n$/,"")}},95344:(e,t,i)=>{"use strict";var s=i(34699),r=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],n=["scalar","sequence","mapping"];e.exports=function(e,t){var i,o;if(t=t||{},Object.keys(t).forEach((function(t){if(-1===r.indexOf(t))throw new s('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=(i=t.styleAliases||null,o={},null!==i&&Object.keys(i).forEach((function(e){i[e].forEach((function(t){o[String(t)]=e}))})),o),-1===n.indexOf(this.kind))throw new s('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}},3389:(e,t,i)=>{"use strict";var s=i(95344),r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";e.exports=new s("tag:yaml.org,2002:binary",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,i,s=0,n=e.length,o=r;for(i=0;i64)){if(t<0)return!1;s+=6}return s%8==0},construct:function(e){var t,i,s=e.replace(/[\r\n=]/g,""),n=s.length,o=r,a=0,c=[];for(t=0;t>16&255),c.push(a>>8&255),c.push(255&a)),a=a<<6|o.indexOf(s.charAt(t));return 0==(i=n%4*6)?(c.push(a>>16&255),c.push(a>>8&255),c.push(255&a)):18===i?(c.push(a>>10&255),c.push(a>>2&255)):12===i&&c.push(a>>4&255),new Uint8Array(c)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){var t,i,s="",n=0,o=e.length,a=r;for(t=0;t>18&63],s+=a[n>>12&63],s+=a[n>>6&63],s+=a[63&n]),n=(n<<8)+e[t];return 0==(i=o%3)?(s+=a[n>>18&63],s+=a[n>>12&63],s+=a[n>>6&63],s+=a[63&n]):2===i?(s+=a[n>>10&63],s+=a[n>>4&63],s+=a[n<<2&63],s+=a[64]):1===i&&(s+=a[n>>2&63],s+=a[n<<4&63],s+=a[64],s+=a[64]),s}})},93691:(e,t,i)=>{"use strict";var s=i(95344);e.exports=new s("tag:yaml.org,2002:bool",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t=e.length;return 4===t&&("true"===e||"True"===e||"TRUE"===e)||5===t&&("false"===e||"False"===e||"FALSE"===e)},construct:function(e){return"true"===e||"True"===e||"TRUE"===e},predicate:function(e){return"[object Boolean]"===Object.prototype.toString.call(e)},represent:{lowercase:function(e){return e?"true":"false"},uppercase:function(e){return e?"TRUE":"FALSE"},camelcase:function(e){return e?"True":"False"}},defaultStyle:"lowercase"})},25948:(e,t,i)=>{"use strict";var s=i(11392),r=i(95344),n=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),o=/^[-+]?[0-9]+e/;e.exports=new r("tag:yaml.org,2002:float",{kind:"scalar",resolve:function(e){return null!==e&&!(!n.test(e)||"_"===e[e.length-1])},construct:function(e){var t,i;return i="-"===(t=e.replace(/_/g,"").toLowerCase())[0]?-1:1,"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===i?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:i*parseFloat(t,10)},predicate:function(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!=0||s.isNegativeZero(e))},represent:function(e,t){var i;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(s.isNegativeZero(e))return"-0.0";return i=e.toString(10),o.test(i)?i.replace("e",".e"):i},defaultStyle:"lowercase"})},30492:(e,t,i)=>{"use strict";var s=i(11392),r=i(95344);function n(e){return 48<=e&&e<=55}function o(e){return 48<=e&&e<=57}e.exports=new r("tag:yaml.org,2002:int",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,i,s=e.length,r=0,a=!1;if(!s)return!1;if("-"!==(t=e[r])&&"+"!==t||(t=e[++r]),"0"===t){if(r+1===s)return!0;if("b"===(t=e[++r])){for(r++;r=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})},69274:(e,t,i)=>{"use strict";var s=i(95344);e.exports=new s("tag:yaml.org,2002:map",{kind:"mapping",construct:function(e){return null!==e?e:{}}})},30945:(e,t,i)=>{"use strict";var s=i(95344);e.exports=new s("tag:yaml.org,2002:merge",{kind:"scalar",resolve:function(e){return"<<"===e||null===e}})},91237:(e,t,i)=>{"use strict";var s=i(95344);e.exports=new s("tag:yaml.org,2002:null",{kind:"scalar",resolve:function(e){if(null===e)return!0;var t=e.length;return 1===t&&"~"===e||4===t&&("null"===e||"Null"===e||"NULL"===e)},construct:function(){return null},predicate:function(e){return null===e},represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"},empty:function(){return""}},defaultStyle:"lowercase"})},4868:(e,t,i)=>{"use strict";var s=i(95344),r=Object.prototype.hasOwnProperty,n=Object.prototype.toString;e.exports=new s("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,i,s,o,a,c=[],l=e;for(t=0,i=l.length;t{"use strict";var s=i(95344),r=Object.prototype.toString;e.exports=new s("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,i,s,n,o,a=e;for(o=new Array(a.length),t=0,i=a.length;t{"use strict";var s=i(95344);e.exports=new s("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(e){return null!==e?e:[]}})},576:(e,t,i)=>{"use strict";var s=i(95344),r=Object.prototype.hasOwnProperty;e.exports=new s("tag:yaml.org,2002:set",{kind:"mapping",resolve:function(e){if(null===e)return!0;var t,i=e;for(t in i)if(r.call(i,t)&&null!==i[t])return!1;return!0},construct:function(e){return null!==e?e:{}}})},43432:(e,t,i)=>{"use strict";var s=i(95344);e.exports=new s("tag:yaml.org,2002:str",{kind:"scalar",construct:function(e){return null!==e?e:""}})},26405:(e,t,i)=>{"use strict";var s=i(95344),r=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),n=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");e.exports=new s("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:function(e){return null!==e&&(null!==r.exec(e)||null!==n.exec(e))},construct:function(e){var t,i,s,o,a,c,l,p,A=0,u=null;if(null===(t=r.exec(e))&&(t=n.exec(e)),null===t)throw new Error("Date resolve error");if(i=+t[1],s=+t[2]-1,o=+t[3],!t[4])return new Date(Date.UTC(i,s,o));if(a=+t[4],c=+t[5],l=+t[6],t[7]){for(A=t[7].slice(0,3);A.length<3;)A+="0";A=+A}return t[9]&&(u=6e4*(60*+t[10]+ +(t[11]||0)),"-"===t[9]&&(u=-u)),p=new Date(Date.UTC(i,s,o,a,c,l,A)),u&&p.setTime(p.getTime()-u),p},instanceOf:Date,represent:function(e){return e.toISOString()}})},79049:e=>{var t=Object.prototype.toString;function i(e){return"function"==typeof e.constructor?e.constructor.name:null}e.exports=function(e){if(void 0===e)return"undefined";if(null===e)return"null";var s=typeof e;if("boolean"===s)return"boolean";if("string"===s)return"string";if("number"===s)return"number";if("symbol"===s)return"symbol";if("function"===s)return"GeneratorFunction"===i(e)?"generatorfunction":"function";if(function(e){return Array.isArray?Array.isArray(e):e instanceof Array}(e))return"array";if(function(e){return!(!e.constructor||"function"!=typeof e.constructor.isBuffer)&&e.constructor.isBuffer(e)}(e))return"buffer";if(function(e){try{if("number"==typeof e.length&&"function"==typeof e.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(e))return"arguments";if(function(e){return e instanceof Date||"function"==typeof e.toDateString&&"function"==typeof e.getDate&&"function"==typeof e.setDate}(e))return"date";if(function(e){return e instanceof Error||"string"==typeof e.message&&e.constructor&&"number"==typeof e.constructor.stackTraceLimit}(e))return"error";if(function(e){return e instanceof RegExp||"string"==typeof e.flags&&"boolean"==typeof e.ignoreCase&&"boolean"==typeof e.multiline&&"boolean"==typeof e.global}(e))return"regexp";switch(i(e)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(e){return"function"==typeof e.throw&&"function"==typeof e.return&&"function"==typeof e.next}(e))return"generator";switch(s=t.call(e)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return s.slice(8,-1).toLowerCase().replace(/\s/g,"")}},6853:(e,t,i)=>{"use strict";const s=i(47309),r=i(5881),n={info:s.blue("ℹ"),success:s.green("✔"),warning:s.yellow("⚠"),error:s.red("✖")},o={info:s.blue("i"),success:s.green("√"),warning:s.yellow("‼"),error:s.red("×")};e.exports=r()?n:o},29416:(e,t,i)=>{"use strict";const s=i(87406),r=Symbol("max"),n=Symbol("length"),o=Symbol("lengthCalculator"),a=Symbol("allowStale"),c=Symbol("maxAge"),l=Symbol("dispose"),p=Symbol("noDisposeOnSet"),A=Symbol("lruList"),u=Symbol("cache"),d=Symbol("updateAgeOnGet"),h=()=>1,m=(e,t,i)=>{const s=e[u].get(t);if(s){const t=s.value;if(g(e,t)){if(E(e,s),!e[a])return}else i&&(e[d]&&(s.value.now=Date.now()),e[A].unshiftNode(s));return t.value}},g=(e,t)=>{if(!t||!t.maxAge&&!e[c])return!1;const i=Date.now()-t.now;return t.maxAge?i>t.maxAge:e[c]&&i>e[c]},f=e=>{if(e[n]>e[r])for(let t=e[A].tail;e[n]>e[r]&&null!==t;){const i=t.prev;E(e,t),t=i}},E=(e,t)=>{if(t){const i=t.value;e[l]&&e[l](i.key,i.value),e[n]-=i.length,e[u].delete(i.key),e[A].removeNode(t)}};class C{constructor(e,t,i,s,r){this.key=e,this.value=t,this.length=i,this.now=s,this.maxAge=r||0}}const y=(e,t,i,s)=>{let r=i.value;g(e,r)&&(E(e,i),e[a]||(r=void 0)),r&&t.call(s,r.value,r.key,e)};e.exports=class{constructor(e){if("number"==typeof e&&(e={max:e}),e||(e={}),e.max&&("number"!=typeof e.max||e.max<0))throw new TypeError("max must be a non-negative number");this[r]=e.max||1/0;const t=e.length||h;if(this[o]="function"!=typeof t?h:t,this[a]=e.stale||!1,e.maxAge&&"number"!=typeof e.maxAge)throw new TypeError("maxAge must be a number");this[c]=e.maxAge||0,this[l]=e.dispose,this[p]=e.noDisposeOnSet||!1,this[d]=e.updateAgeOnGet||!1,this.reset()}set max(e){if("number"!=typeof e||e<0)throw new TypeError("max must be a non-negative number");this[r]=e||1/0,f(this)}get max(){return this[r]}set allowStale(e){this[a]=!!e}get allowStale(){return this[a]}set maxAge(e){if("number"!=typeof e)throw new TypeError("maxAge must be a non-negative number");this[c]=e,f(this)}get maxAge(){return this[c]}set lengthCalculator(e){"function"!=typeof e&&(e=h),e!==this[o]&&(this[o]=e,this[n]=0,this[A].forEach((e=>{e.length=this[o](e.value,e.key),this[n]+=e.length}))),f(this)}get lengthCalculator(){return this[o]}get length(){return this[n]}get itemCount(){return this[A].length}rforEach(e,t){t=t||this;for(let i=this[A].tail;null!==i;){const s=i.prev;y(this,e,i,t),i=s}}forEach(e,t){t=t||this;for(let i=this[A].head;null!==i;){const s=i.next;y(this,e,i,t),i=s}}keys(){return this[A].toArray().map((e=>e.key))}values(){return this[A].toArray().map((e=>e.value))}reset(){this[l]&&this[A]&&this[A].length&&this[A].forEach((e=>this[l](e.key,e.value))),this[u]=new Map,this[A]=new s,this[n]=0}dump(){return this[A].map((e=>!g(this,e)&&{k:e.key,v:e.value,e:e.now+(e.maxAge||0)})).toArray().filter((e=>e))}dumpLru(){return this[A]}set(e,t,i){if((i=i||this[c])&&"number"!=typeof i)throw new TypeError("maxAge must be a number");const s=i?Date.now():0,a=this[o](t,e);if(this[u].has(e)){if(a>this[r])return E(this,this[u].get(e)),!1;const o=this[u].get(e).value;return this[l]&&(this[p]||this[l](e,o.value)),o.now=s,o.maxAge=i,o.value=t,this[n]+=a-o.length,o.length=a,this.get(e),f(this),!0}const d=new C(e,t,a,s,i);return d.length>this[r]?(this[l]&&this[l](e,t),!1):(this[n]+=d.length,this[A].unshift(d),this[u].set(e,this[A].head),f(this),!0)}has(e){if(!this[u].has(e))return!1;const t=this[u].get(e).value;return!g(this,t)}get(e){return m(this,e,!0)}peek(e){return m(this,e,!1)}pop(){const e=this[A].tail;return e?(E(this,e),e.value):null}del(e){E(this,this[u].get(e))}load(e){this.reset();const t=Date.now();for(let i=e.length-1;i>=0;i--){const s=e[i],r=s.e||0;if(0===r)this.set(s.k,s.v);else{const e=r-t;e>0&&this.set(s.k,s.v,e)}}}prune(){this[u].forEach(((e,t)=>m(this,t,!1)))}}},69759:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});class i extends Error{}class s extends i{constructor(e){super(`Invalid DateTime: ${e.toMessage()}`)}}class r extends i{constructor(e){super(`Invalid Interval: ${e.toMessage()}`)}}class n extends i{constructor(e){super(`Invalid Duration: ${e.toMessage()}`)}}class o extends i{}class a extends i{constructor(e){super(`Invalid unit ${e}`)}}class c extends i{}class l extends i{constructor(){super("Zone is an abstract class")}}const p="numeric",A="short",u="long",d={year:p,month:p,day:p},h={year:p,month:A,day:p},m={year:p,month:A,day:p,weekday:A},g={year:p,month:u,day:p},f={year:p,month:u,day:p,weekday:u},E={hour:p,minute:p},C={hour:p,minute:p,second:p},y={hour:p,minute:p,second:p,timeZoneName:A},v={hour:p,minute:p,second:p,timeZoneName:u},I={hour:p,minute:p,hourCycle:"h23"},B={hour:p,minute:p,second:p,hourCycle:"h23"},w={hour:p,minute:p,second:p,hourCycle:"h23",timeZoneName:A},b={hour:p,minute:p,second:p,hourCycle:"h23",timeZoneName:u},Q={year:p,month:p,day:p,hour:p,minute:p},x={year:p,month:p,day:p,hour:p,minute:p,second:p},k={year:p,month:A,day:p,hour:p,minute:p},D={year:p,month:A,day:p,hour:p,minute:p,second:p},S={year:p,month:A,day:p,weekday:A,hour:p,minute:p},_={year:p,month:u,day:p,hour:p,minute:p,timeZoneName:A},R={year:p,month:u,day:p,hour:p,minute:p,second:p,timeZoneName:A},T={year:p,month:u,day:p,weekday:u,hour:p,minute:p,timeZoneName:u},F={year:p,month:u,day:p,weekday:u,hour:p,minute:p,second:p,timeZoneName:u};class N{get type(){throw new l}get name(){throw new l}get ianaName(){return this.name}get isUniversal(){throw new l}offsetName(e,t){throw new l}formatOffset(e,t){throw new l}offset(e){throw new l}equals(e){throw new l}get isValid(){throw new l}}let L=null;class O extends N{static get instance(){return null===L&&(L=new O),L}get type(){return"system"}get name(){return(new Intl.DateTimeFormat).resolvedOptions().timeZone}get isUniversal(){return!1}offsetName(e,{format:t,locale:i}){return $e(e,t,i)}formatOffset(e,t){return et(this.offset(e),t)}offset(e){return-new Date(e).getTimezoneOffset()}equals(e){return"system"===e.type}get isValid(){return!0}}let M={};const U={year:0,month:1,day:2,era:3,hour:4,minute:5,second:6};let P={};class G extends N{static create(e){return P[e]||(P[e]=new G(e)),P[e]}static resetCache(){P={},M={}}static isValidSpecifier(e){return this.isValidZone(e)}static isValidZone(e){if(!e)return!1;try{return new Intl.DateTimeFormat("en-US",{timeZone:e}).format(),!0}catch(e){return!1}}constructor(e){super(),this.zoneName=e,this.valid=G.isValidZone(e)}get type(){return"iana"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(e,{format:t,locale:i}){return $e(e,t,i,this.name)}formatOffset(e,t){return et(this.offset(e),t)}offset(e){const t=new Date(e);if(isNaN(t))return NaN;const i=(s=this.name,M[s]||(M[s]=new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:s,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",era:"short"})),M[s]);var s;let[r,n,o,a,c,l,p]=i.formatToParts?function(e,t){const i=e.formatToParts(t),s=[];for(let e=0;e=0?u:1e3+u,(qe({year:r,month:n,day:o,hour:24===c?0:c,minute:l,second:p,millisecond:0})-A)/6e4}equals(e){return"iana"===e.type&&e.name===this.name}get isValid(){return this.valid}}let V={},j={};function H(e,t={}){const i=JSON.stringify([e,t]);let s=j[i];return s||(s=new Intl.DateTimeFormat(e,t),j[i]=s),s}let J={},q={},Y=null,W={};function z(e,t,i,s){const r=e.listingMode();return"error"===r?null:"en"===r?i(t):s(t)}class ${constructor(e,t,i){this.padTo=i.padTo||0,this.floor=i.floor||!1;const{padTo:s,floor:r,...n}=i;if(!t||Object.keys(n).length>0){const t={useGrouping:!1,...i};i.padTo>0&&(t.minimumIntegerDigits=i.padTo),this.inf=function(e,t={}){const i=JSON.stringify([e,t]);let s=J[i];return s||(s=new Intl.NumberFormat(e,t),J[i]=s),s}(e,t)}}format(e){if(this.inf){const t=this.floor?Math.floor(e):e;return this.inf.format(t)}return Me(this.floor?Math.floor(e):Ve(e,3),this.padTo)}}class X{constructor(e,t,i){let s;if(this.opts=i,this.originalZone=void 0,this.opts.timeZone)this.dt=e;else if("fixed"===e.zone.type){const t=e.offset/60*-1,i=t>=0?`Etc/GMT+${t}`:`Etc/GMT${t}`;0!==e.offset&&G.create(i).valid?(s=i,this.dt=e):(s="UTC",this.dt=0===e.offset?e:e.setZone("UTC").plus({minutes:e.offset}),this.originalZone=e.zone)}else"system"===e.zone.type?this.dt=e:"iana"===e.zone.type?(this.dt=e,s=e.zone.name):(s="UTC",this.dt=e.setZone("UTC").plus({minutes:e.offset}),this.originalZone=e.zone);const r={...this.opts};r.timeZone=r.timeZone||s,this.dtf=H(t,r)}format(){return this.originalZone?this.formatToParts().map((({value:e})=>e)).join(""):this.dtf.format(this.dt.toJSDate())}formatToParts(){const e=this.dtf.formatToParts(this.dt.toJSDate());return this.originalZone?e.map((e=>{if("timeZoneName"===e.type){const t=this.originalZone.offsetName(this.dt.ts,{locale:this.dt.locale,format:this.opts.timeZoneName});return{...e,value:t}}return e})):e}resolvedOptions(){return this.dtf.resolvedOptions()}}class K{constructor(e,t,i){this.opts={style:"long",...i},!t&&Re()&&(this.rtf=function(e,t={}){const{base:i,...s}=t,r=JSON.stringify([e,s]);let n=q[r];return n||(n=new Intl.RelativeTimeFormat(e,t),q[r]=n),n}(e,i))}format(e,t){return this.rtf?this.rtf.format(e,t):function(e,t,i="always",s=!1){const r={years:["year","yr."],quarters:["quarter","qtr."],months:["month","mo."],weeks:["week","wk."],days:["day","day","days"],hours:["hour","hr."],minutes:["minute","min."],seconds:["second","sec."]},n=-1===["hours","minutes","seconds"].indexOf(e);if("auto"===i&&n){const i="days"===e;switch(t){case 1:return i?"tomorrow":`next ${r[e][0]}`;case-1:return i?"yesterday":`last ${r[e][0]}`;case 0:return i?"today":`this ${r[e][0]}`}}const o=Object.is(t,-0)||t<0,a=Math.abs(t),c=1===a,l=r[e],p=s?c?l[1]:l[2]||l[1]:c?r[e][0]:e;return o?`${a} ${p} ago`:`in ${a} ${p}`}(t,e,this.opts.numeric,"long"!==this.opts.style)}formatToParts(e,t){return this.rtf?this.rtf.formatToParts(e,t):[]}}const Z={firstDay:1,minimalDays:4,weekend:[6,7]};class ee{static fromOpts(e){return ee.create(e.locale,e.numberingSystem,e.outputCalendar,e.weekSettings,e.defaultToEN)}static create(e,t,i,s,r=!1){const n=e||de.defaultLocale,o=n||(r?"en-US":Y||(Y=(new Intl.DateTimeFormat).resolvedOptions().locale,Y)),a=t||de.defaultNumberingSystem,c=i||de.defaultOutputCalendar,l=Le(s)||de.defaultWeekSettings;return new ee(o,a,c,l,n)}static resetCache(){Y=null,j={},J={},q={}}static fromObject({locale:e,numberingSystem:t,outputCalendar:i,weekSettings:s}={}){return ee.create(e,t,i,s)}constructor(e,t,i,s,r){const[n,o,a]=function(e){const t=e.indexOf("-x-");-1!==t&&(e=e.substring(0,t));const i=e.indexOf("-u-");if(-1===i)return[e];{let t,s;try{t=H(e).resolvedOptions(),s=e}catch(r){const n=e.substring(0,i);t=H(n).resolvedOptions(),s=n}const{numberingSystem:r,calendar:n}=t;return[s,r,n]}}(e);this.locale=n,this.numberingSystem=t||o||null,this.outputCalendar=i||a||null,this.weekSettings=s,this.intl=function(e,t,i){return i||t?(e.includes("-u-")||(e+="-u"),i&&(e+=`-ca-${i}`),t&&(e+=`-nu-${t}`),e):e}(this.locale,this.numberingSystem,this.outputCalendar),this.weekdaysCache={format:{},standalone:{}},this.monthsCache={format:{},standalone:{}},this.meridiemCache=null,this.eraCache={},this.specifiedLocale=r,this.fastNumbersCached=null}get fastNumbers(){var e;return null==this.fastNumbersCached&&(this.fastNumbersCached=(!(e=this).numberingSystem||"latn"===e.numberingSystem)&&("latn"===e.numberingSystem||!e.locale||e.locale.startsWith("en")||"latn"===new Intl.DateTimeFormat(e.intl).resolvedOptions().numberingSystem)),this.fastNumbersCached}listingMode(){const e=this.isEnglish(),t=!(null!==this.numberingSystem&&"latn"!==this.numberingSystem||null!==this.outputCalendar&&"gregory"!==this.outputCalendar);return e&&t?"en":"intl"}clone(e){return e&&0!==Object.getOwnPropertyNames(e).length?ee.create(e.locale||this.specifiedLocale,e.numberingSystem||this.numberingSystem,e.outputCalendar||this.outputCalendar,Le(e.weekSettings)||this.weekSettings,e.defaultToEN||!1):this}redefaultToEN(e={}){return this.clone({...e,defaultToEN:!0})}redefaultToSystem(e={}){return this.clone({...e,defaultToEN:!1})}months(e,t=!1){return z(this,e,nt,(()=>{const i=t?{month:e,day:"numeric"}:{month:e},s=t?"format":"standalone";return this.monthsCache[s][e]||(this.monthsCache[s][e]=function(e){const t=[];for(let i=1;i<=12;i++){const s=os.utc(2009,i,1);t.push(e(s))}return t}((e=>this.extract(e,i,"month")))),this.monthsCache[s][e]}))}weekdays(e,t=!1){return z(this,e,lt,(()=>{const i=t?{weekday:e,year:"numeric",month:"long",day:"numeric"}:{weekday:e},s=t?"format":"standalone";return this.weekdaysCache[s][e]||(this.weekdaysCache[s][e]=function(e){const t=[];for(let i=1;i<=7;i++){const s=os.utc(2016,11,13+i);t.push(e(s))}return t}((e=>this.extract(e,i,"weekday")))),this.weekdaysCache[s][e]}))}meridiems(){return z(this,void 0,(()=>pt),(()=>{if(!this.meridiemCache){const e={hour:"numeric",hourCycle:"h12"};this.meridiemCache=[os.utc(2016,11,13,9),os.utc(2016,11,13,19)].map((t=>this.extract(t,e,"dayperiod")))}return this.meridiemCache}))}eras(e){return z(this,e,ht,(()=>{const t={era:e};return this.eraCache[e]||(this.eraCache[e]=[os.utc(-40,1,1),os.utc(2017,1,1)].map((e=>this.extract(e,t,"era")))),this.eraCache[e]}))}extract(e,t,i){const s=this.dtFormatter(e,t).formatToParts().find((e=>e.type.toLowerCase()===i));return s?s.value:null}numberFormatter(e={}){return new $(this.intl,e.forceSimple||this.fastNumbers,e)}dtFormatter(e,t={}){return new X(e,this.intl,t)}relFormatter(e={}){return new K(this.intl,this.isEnglish(),e)}listFormatter(e={}){return function(e,t={}){const i=JSON.stringify([e,t]);let s=V[i];return s||(s=new Intl.ListFormat(e,t),V[i]=s),s}(this.intl,e)}isEnglish(){return"en"===this.locale||"en-us"===this.locale.toLowerCase()||new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us")}getWeekSettings(){return this.weekSettings?this.weekSettings:Te()?function(e){let t=W[e];if(!t){const i=new Intl.Locale(e);t="getWeekInfo"in i?i.getWeekInfo():i.weekInfo,W[e]=t}return t}(this.locale):Z}getStartOfWeek(){return this.getWeekSettings().firstDay}getMinDaysInFirstWeek(){return this.getWeekSettings().minimalDays}getWeekendDays(){return this.getWeekSettings().weekend}equals(e){return this.locale===e.locale&&this.numberingSystem===e.numberingSystem&&this.outputCalendar===e.outputCalendar}}let te=null;class ie extends N{static get utcInstance(){return null===te&&(te=new ie(0)),te}static instance(e){return 0===e?ie.utcInstance:new ie(e)}static parseSpecifier(e){if(e){const t=e.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);if(t)return new ie(Xe(t[1],t[2]))}return null}constructor(e){super(),this.fixed=e}get type(){return"fixed"}get name(){return 0===this.fixed?"UTC":`UTC${et(this.fixed,"narrow")}`}get ianaName(){return 0===this.fixed?"Etc/UTC":`Etc/GMT${et(-this.fixed,"narrow")}`}offsetName(){return this.name}formatOffset(e,t){return et(this.fixed,t)}get isUniversal(){return!0}offset(){return this.fixed}equals(e){return"fixed"===e.type&&e.fixed===this.fixed}get isValid(){return!0}}class se extends N{constructor(e){super(),this.zoneName=e}get type(){return"invalid"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(){return null}formatOffset(){return""}offset(){return NaN}equals(){return!1}get isValid(){return!1}}function re(e,t){if(De(e)||null===e)return t;if(e instanceof N)return e;if("string"==typeof e){const i=e.toLowerCase();return"default"===i?t:"local"===i||"system"===i?O.instance:"utc"===i||"gmt"===i?ie.utcInstance:ie.parseSpecifier(i)||G.create(e)}return Se(e)?ie.instance(e):"object"==typeof e&&"offset"in e&&"function"==typeof e.offset?e:new se(e)}let ne,oe=()=>Date.now(),ae="system",ce=null,le=null,pe=null,Ae=60,ue=null;class de{static get now(){return oe}static set now(e){oe=e}static set defaultZone(e){ae=e}static get defaultZone(){return re(ae,O.instance)}static get defaultLocale(){return ce}static set defaultLocale(e){ce=e}static get defaultNumberingSystem(){return le}static set defaultNumberingSystem(e){le=e}static get defaultOutputCalendar(){return pe}static set defaultOutputCalendar(e){pe=e}static get defaultWeekSettings(){return ue}static set defaultWeekSettings(e){ue=Le(e)}static get twoDigitCutoffYear(){return Ae}static set twoDigitCutoffYear(e){Ae=e%100}static get throwOnInvalid(){return ne}static set throwOnInvalid(e){ne=e}static resetCaches(){ee.resetCache(),G.resetCache()}}class he{constructor(e,t){this.reason=e,this.explanation=t}toMessage(){return this.explanation?`${this.reason}: ${this.explanation}`:this.reason}}const me=[0,31,59,90,120,151,181,212,243,273,304,334],ge=[0,31,60,91,121,152,182,213,244,274,305,335];function fe(e,t){return new he("unit out of range",`you specified ${t} (of type ${typeof t}) as a ${e}, which is invalid`)}function Ee(e,t,i){const s=new Date(Date.UTC(e,t-1,i));e<100&&e>=0&&s.setUTCFullYear(s.getUTCFullYear()-1900);const r=s.getUTCDay();return 0===r?7:r}function Ce(e,t,i){return i+(je(e)?ge:me)[t-1]}function ye(e,t){const i=je(e)?ge:me,s=i.findIndex((e=>eWe(s,t,i)?(c=s+1,l=1):c=s,{weekYear:c,weekNumber:l,weekday:a,...tt(e)}}function Be(e,t=4,i=1){const{weekYear:s,weekNumber:r,weekday:n}=e,o=ve(Ee(s,1,t),i),a=He(s);let c,l=7*r+n-o-7+t;l<1?(c=s-1,l+=He(c)):l>a?(c=s+1,l-=He(s)):c=s;const{month:p,day:A}=ye(c,l);return{year:c,month:p,day:A,...tt(e)}}function we(e){const{year:t,month:i,day:s}=e;return{year:t,ordinal:Ce(t,i,s),...tt(e)}}function be(e){const{year:t,ordinal:i}=e,{month:s,day:r}=ye(t,i);return{year:t,month:s,day:r,...tt(e)}}function Qe(e,t){if(!De(e.localWeekday)||!De(e.localWeekNumber)||!De(e.localWeekYear)){if(!De(e.weekday)||!De(e.weekNumber)||!De(e.weekYear))throw new o("Cannot mix locale-based week fields with ISO-based week fields");return De(e.localWeekday)||(e.weekday=e.localWeekday),De(e.localWeekNumber)||(e.weekNumber=e.localWeekNumber),De(e.localWeekYear)||(e.weekYear=e.localWeekYear),delete e.localWeekday,delete e.localWeekNumber,delete e.localWeekYear,{minDaysInFirstWeek:t.getMinDaysInFirstWeek(),startOfWeek:t.getStartOfWeek()}}return{minDaysInFirstWeek:4,startOfWeek:1}}function xe(e){const t=_e(e.year),i=Oe(e.month,1,12),s=Oe(e.day,1,Je(e.year,e.month));return t?i?!s&&fe("day",e.day):fe("month",e.month):fe("year",e.year)}function ke(e){const{hour:t,minute:i,second:s,millisecond:r}=e,n=Oe(t,0,23)||24===t&&0===i&&0===s&&0===r,o=Oe(i,0,59),a=Oe(s,0,59),c=Oe(r,0,999);return n?o?a?!c&&fe("millisecond",r):fe("second",s):fe("minute",i):fe("hour",t)}function De(e){return void 0===e}function Se(e){return"number"==typeof e}function _e(e){return"number"==typeof e&&e%1==0}function Re(){try{return"undefined"!=typeof Intl&&!!Intl.RelativeTimeFormat}catch(e){return!1}}function Te(){try{return"undefined"!=typeof Intl&&!!Intl.Locale&&("weekInfo"in Intl.Locale.prototype||"getWeekInfo"in Intl.Locale.prototype)}catch(e){return!1}}function Fe(e,t,i){if(0!==e.length)return e.reduce(((e,s)=>{const r=[t(s),s];return e&&i(e[0],r[0])===e[0]?e:r}),null)[1]}function Ne(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function Le(e){if(null==e)return null;if("object"!=typeof e)throw new c("Week settings must be an object");if(!Oe(e.firstDay,1,7)||!Oe(e.minimalDays,1,7)||!Array.isArray(e.weekend)||e.weekend.some((e=>!Oe(e,1,7))))throw new c("Invalid week settings");return{firstDay:e.firstDay,minimalDays:e.minimalDays,weekend:Array.from(e.weekend)}}function Oe(e,t,i){return _e(e)&&e>=t&&e<=i}function Me(e,t=2){let i;return i=e<0?"-"+(""+-e).padStart(t,"0"):(""+e).padStart(t,"0"),i}function Ue(e){return De(e)||null===e||""===e?void 0:parseInt(e,10)}function Pe(e){return De(e)||null===e||""===e?void 0:parseFloat(e)}function Ge(e){if(!De(e)&&null!==e&&""!==e){const t=1e3*parseFloat("0."+e);return Math.floor(t)}}function Ve(e,t,i=!1){const s=10**t;return(i?Math.trunc:Math.round)(e*s)/s}function je(e){return e%4==0&&(e%100!=0||e%400==0)}function He(e){return je(e)?366:365}function Je(e,t){const i=(s=t-1)-12*Math.floor(s/12)+1;var s;return 2===i?je(e+(t-i)/12)?29:28:[31,null,31,30,31,30,31,31,30,31,30,31][i-1]}function qe(e){let t=Date.UTC(e.year,e.month-1,e.day,e.hour,e.minute,e.second,e.millisecond);return e.year<100&&e.year>=0&&(t=new Date(t),t.setUTCFullYear(e.year,e.month-1,e.day)),+t}function Ye(e,t,i){return-ve(Ee(e,1,t),i)+t-1}function We(e,t=4,i=1){const s=Ye(e,t,i),r=Ye(e+1,t,i);return(He(e)-s+r)/7}function ze(e){return e>99?e:e>de.twoDigitCutoffYear?1900+e:2e3+e}function $e(e,t,i,s=null){const r=new Date(e),n={hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"};s&&(n.timeZone=s);const o={timeZoneName:t,...n},a=new Intl.DateTimeFormat(i,o).formatToParts(r).find((e=>"timezonename"===e.type.toLowerCase()));return a?a.value:null}function Xe(e,t){let i=parseInt(e,10);Number.isNaN(i)&&(i=0);const s=parseInt(t,10)||0;return 60*i+(i<0||Object.is(i,-0)?-s:s)}function Ke(e){const t=Number(e);if("boolean"==typeof e||""===e||Number.isNaN(t))throw new c(`Invalid unit value ${e}`);return t}function Ze(e,t){const i={};for(const s in e)if(Ne(e,s)){const r=e[s];if(null==r)continue;i[t(s)]=Ke(r)}return i}function et(e,t){const i=Math.trunc(Math.abs(e/60)),s=Math.trunc(Math.abs(e%60)),r=e>=0?"+":"-";switch(t){case"short":return`${r}${Me(i,2)}:${Me(s,2)}`;case"narrow":return`${r}${i}${s>0?`:${s}`:""}`;case"techie":return`${r}${Me(i,2)}${Me(s,2)}`;default:throw new RangeError(`Value format ${t} is out of range for property format`)}}function tt(e){return function(e,t){return["hour","minute","second","millisecond"].reduce(((t,i)=>(t[i]=e[i],t)),{})}(e)}const it=["January","February","March","April","May","June","July","August","September","October","November","December"],st=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],rt=["J","F","M","A","M","J","J","A","S","O","N","D"];function nt(e){switch(e){case"narrow":return[...rt];case"short":return[...st];case"long":return[...it];case"numeric":return["1","2","3","4","5","6","7","8","9","10","11","12"];case"2-digit":return["01","02","03","04","05","06","07","08","09","10","11","12"];default:return null}}const ot=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],at=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],ct=["M","T","W","T","F","S","S"];function lt(e){switch(e){case"narrow":return[...ct];case"short":return[...at];case"long":return[...ot];case"numeric":return["1","2","3","4","5","6","7"];default:return null}}const pt=["AM","PM"],At=["Before Christ","Anno Domini"],ut=["BC","AD"],dt=["B","A"];function ht(e){switch(e){case"narrow":return[...dt];case"short":return[...ut];case"long":return[...At];default:return null}}function mt(e,t){let i="";for(const s of e)s.literal?i+=s.val:i+=t(s.val);return i}const gt={D:d,DD:h,DDD:g,DDDD:f,t:E,tt:C,ttt:y,tttt:v,T:I,TT:B,TTT:w,TTTT:b,f:Q,ff:k,fff:_,ffff:T,F:x,FF:D,FFF:R,FFFF:F};class ft{static create(e,t={}){return new ft(e,t)}static parseFormat(e){let t=null,i="",s=!1;const r=[];for(let n=0;n0&&r.push({literal:s||/^\s+$/.test(i),val:i}),t=null,i="",s=!s):s||o===t?i+=o:(i.length>0&&r.push({literal:/^\s+$/.test(i),val:i}),i=o,t=o)}return i.length>0&&r.push({literal:s||/^\s+$/.test(i),val:i}),r}static macroTokenToFormatOpts(e){return gt[e]}constructor(e,t){this.opts=t,this.loc=e,this.systemLoc=null}formatWithSystemDefault(e,t){return null===this.systemLoc&&(this.systemLoc=this.loc.redefaultToSystem()),this.systemLoc.dtFormatter(e,{...this.opts,...t}).format()}dtFormatter(e,t={}){return this.loc.dtFormatter(e,{...this.opts,...t})}formatDateTime(e,t){return this.dtFormatter(e,t).format()}formatDateTimeParts(e,t){return this.dtFormatter(e,t).formatToParts()}formatInterval(e,t){return this.dtFormatter(e.start,t).dtf.formatRange(e.start.toJSDate(),e.end.toJSDate())}resolvedOptions(e,t){return this.dtFormatter(e,t).resolvedOptions()}num(e,t=0){if(this.opts.forceSimple)return Me(e,t);const i={...this.opts};return t>0&&(i.padTo=t),this.loc.numberFormatter(i).format(e)}formatDateTimeFromString(e,t){const i="en"===this.loc.listingMode(),s=this.loc.outputCalendar&&"gregory"!==this.loc.outputCalendar,r=(t,i)=>this.loc.extract(e,t,i),n=t=>e.isOffsetFixed&&0===e.offset&&t.allowZ?"Z":e.isValid?e.zone.formatOffset(e.ts,t.format):"",o=(t,s)=>i?function(e,t){return nt(t)[e.month-1]}(e,t):r(s?{month:t}:{month:t,day:"numeric"},"month"),a=(t,s)=>i?function(e,t){return lt(t)[e.weekday-1]}(e,t):r(s?{weekday:t}:{weekday:t,month:"long",day:"numeric"},"weekday"),c=t=>{const i=ft.macroTokenToFormatOpts(t);return i?this.formatWithSystemDefault(e,i):t},l=t=>i?function(e,t){return ht(t)[e.year<0?0:1]}(e,t):r({era:t},"era");return mt(ft.parseFormat(t),(t=>{switch(t){case"S":return this.num(e.millisecond);case"u":case"SSS":return this.num(e.millisecond,3);case"s":return this.num(e.second);case"ss":return this.num(e.second,2);case"uu":return this.num(Math.floor(e.millisecond/10),2);case"uuu":return this.num(Math.floor(e.millisecond/100));case"m":return this.num(e.minute);case"mm":return this.num(e.minute,2);case"h":return this.num(e.hour%12==0?12:e.hour%12);case"hh":return this.num(e.hour%12==0?12:e.hour%12,2);case"H":return this.num(e.hour);case"HH":return this.num(e.hour,2);case"Z":return n({format:"narrow",allowZ:this.opts.allowZ});case"ZZ":return n({format:"short",allowZ:this.opts.allowZ});case"ZZZ":return n({format:"techie",allowZ:this.opts.allowZ});case"ZZZZ":return e.zone.offsetName(e.ts,{format:"short",locale:this.loc.locale});case"ZZZZZ":return e.zone.offsetName(e.ts,{format:"long",locale:this.loc.locale});case"z":return e.zoneName;case"a":return i?function(e){return pt[e.hour<12?0:1]}(e):r({hour:"numeric",hourCycle:"h12"},"dayperiod");case"d":return s?r({day:"numeric"},"day"):this.num(e.day);case"dd":return s?r({day:"2-digit"},"day"):this.num(e.day,2);case"c":case"E":return this.num(e.weekday);case"ccc":return a("short",!0);case"cccc":return a("long",!0);case"ccccc":return a("narrow",!0);case"EEE":return a("short",!1);case"EEEE":return a("long",!1);case"EEEEE":return a("narrow",!1);case"L":return s?r({month:"numeric",day:"numeric"},"month"):this.num(e.month);case"LL":return s?r({month:"2-digit",day:"numeric"},"month"):this.num(e.month,2);case"LLL":return o("short",!0);case"LLLL":return o("long",!0);case"LLLLL":return o("narrow",!0);case"M":return s?r({month:"numeric"},"month"):this.num(e.month);case"MM":return s?r({month:"2-digit"},"month"):this.num(e.month,2);case"MMM":return o("short",!1);case"MMMM":return o("long",!1);case"MMMMM":return o("narrow",!1);case"y":return s?r({year:"numeric"},"year"):this.num(e.year);case"yy":return s?r({year:"2-digit"},"year"):this.num(e.year.toString().slice(-2),2);case"yyyy":return s?r({year:"numeric"},"year"):this.num(e.year,4);case"yyyyyy":return s?r({year:"numeric"},"year"):this.num(e.year,6);case"G":return l("short");case"GG":return l("long");case"GGGGG":return l("narrow");case"kk":return this.num(e.weekYear.toString().slice(-2),2);case"kkkk":return this.num(e.weekYear,4);case"W":return this.num(e.weekNumber);case"WW":return this.num(e.weekNumber,2);case"n":return this.num(e.localWeekNumber);case"nn":return this.num(e.localWeekNumber,2);case"ii":return this.num(e.localWeekYear.toString().slice(-2),2);case"iiii":return this.num(e.localWeekYear,4);case"o":return this.num(e.ordinal);case"ooo":return this.num(e.ordinal,3);case"q":return this.num(e.quarter);case"qq":return this.num(e.quarter,2);case"X":return this.num(Math.floor(e.ts/1e3));case"x":return this.num(e.ts);default:return c(t)}}))}formatDurationFromString(e,t){const i=e=>{switch(e[0]){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":return"hour";case"d":return"day";case"w":return"week";case"M":return"month";case"y":return"year";default:return null}},s=ft.parseFormat(t),r=s.reduce(((e,{literal:t,val:i})=>t?e:e.concat(i)),[]);return mt(s,(e=>t=>{const s=i(t);return s?this.num(e.get(s),t.length):t})(e.shiftTo(...r.map(i).filter((e=>e)))))}}const Et=/[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;function Ct(...e){const t=e.reduce(((e,t)=>e+t.source),"");return RegExp(`^${t}$`)}function yt(...e){return t=>e.reduce((([e,i,s],r)=>{const[n,o,a]=r(t,s);return[{...e,...n},o||i,a]}),[{},null,1]).slice(0,2)}function vt(e,...t){if(null==e)return[null,null];for(const[i,s]of t){const t=i.exec(e);if(t)return s(t)}return[null,null]}function It(...e){return(t,i)=>{const s={};let r;for(r=0;rvoid 0!==e&&(t||e&&p)?-e:e;return[{years:u(Pe(i)),months:u(Pe(s)),weeks:u(Pe(r)),days:u(Pe(n)),hours:u(Pe(o)),minutes:u(Pe(a)),seconds:u(Pe(c),"-0"===c),milliseconds:u(Ge(l),A)}]}const Mt={GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ut(e,t,i,s,r,n,o){const a={year:2===t.length?ze(Ue(t)):Ue(t),month:st.indexOf(i)+1,day:Ue(s),hour:Ue(r),minute:Ue(n)};return o&&(a.second=Ue(o)),e&&(a.weekday=e.length>3?ot.indexOf(e)+1:at.indexOf(e)+1),a}const Pt=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;function Gt(e){const[,t,i,s,r,n,o,a,c,l,p,A]=e,u=Ut(t,r,s,i,n,o,a);let d;return d=c?Mt[c]:l?0:Xe(p,A),[u,new ie(d)]}const Vt=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,jt=/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,Ht=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;function Jt(e){const[,t,i,s,r,n,o,a]=e;return[Ut(t,r,s,i,n,o,a),ie.utcInstance]}function qt(e){const[,t,i,s,r,n,o,a]=e;return[Ut(t,a,i,s,r,n,o),ie.utcInstance]}const Yt=Ct(/([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/,Qt),Wt=Ct(/(\d{4})-?W(\d\d)(?:-?(\d))?/,Qt),zt=Ct(/(\d{4})-?(\d{3})/,Qt),$t=Ct(bt),Xt=yt((function(e,t){return[{year:_t(e,t),month:_t(e,t+1,1),day:_t(e,t+2,1)},null,t+3]}),Rt,Tt,Ft),Kt=yt(xt,Rt,Tt,Ft),Zt=yt(kt,Rt,Tt,Ft),ei=yt(Rt,Tt,Ft),ti=yt(Rt),ii=Ct(/(\d{4})-(\d\d)-(\d\d)/,St),si=Ct(Dt),ri=yt(Rt,Tt,Ft),ni="Invalid Duration",oi={weeks:{days:7,hours:168,minutes:10080,seconds:604800,milliseconds:6048e5},days:{hours:24,minutes:1440,seconds:86400,milliseconds:864e5},hours:{minutes:60,seconds:3600,milliseconds:36e5},minutes:{seconds:60,milliseconds:6e4},seconds:{milliseconds:1e3}},ai={years:{quarters:4,months:12,weeks:52,days:365,hours:8760,minutes:525600,seconds:31536e3,milliseconds:31536e6},quarters:{months:3,weeks:13,days:91,hours:2184,minutes:131040,seconds:7862400,milliseconds:78624e5},months:{weeks:4,days:30,hours:720,minutes:43200,seconds:2592e3,milliseconds:2592e6},...oi},ci={years:{quarters:4,months:12,weeks:52.1775,days:365.2425,hours:8765.82,minutes:525949.2,seconds:525949.2*60,milliseconds:525949.2*60*1e3},quarters:{months:3,weeks:13.044375,days:91.310625,hours:2191.455,minutes:131487.3,seconds:525949.2*60/4,milliseconds:7889237999.999999},months:{weeks:4.3481250000000005,days:30.436875,hours:730.485,minutes:43829.1,seconds:2629746,milliseconds:2629746e3},...oi},li=["years","quarters","months","weeks","days","hours","minutes","seconds","milliseconds"],pi=li.slice(0).reverse();function Ai(e,t,i=!1){const s={values:i?t.values:{...e.values,...t.values||{}},loc:e.loc.clone(t.loc),conversionAccuracy:t.conversionAccuracy||e.conversionAccuracy,matrix:t.matrix||e.matrix};return new hi(s)}function ui(e,t){var i;let s=null!=(i=t.milliseconds)?i:0;for(const i of pi.slice(1))t[i]&&(s+=t[i]*e[i].milliseconds);return s}function di(e,t){const i=ui(e,t)<0?-1:1;li.reduceRight(((s,r)=>{if(De(t[r]))return s;if(s){const n=t[s]*i,o=e[r][s],a=Math.floor(n/o);t[r]+=a*i,t[s]-=a*o*i}return r}),null),li.reduce(((i,s)=>{if(De(t[s]))return i;if(i){const r=t[i]%1;t[i]-=r,t[s]+=r*e[i][s]}return s}),null)}class hi{constructor(e){const t="longterm"===e.conversionAccuracy||!1;let i=t?ci:ai;e.matrix&&(i=e.matrix),this.values=e.values,this.loc=e.loc||ee.create(),this.conversionAccuracy=t?"longterm":"casual",this.invalid=e.invalid||null,this.matrix=i,this.isLuxonDuration=!0}static fromMillis(e,t){return hi.fromObject({milliseconds:e},t)}static fromObject(e,t={}){if(null==e||"object"!=typeof e)throw new c("Duration.fromObject: argument expected to be an object, got "+(null===e?"null":typeof e));return new hi({values:Ze(e,hi.normalizeUnit),loc:ee.fromObject(t),conversionAccuracy:t.conversionAccuracy,matrix:t.matrix})}static fromDurationLike(e){if(Se(e))return hi.fromMillis(e);if(hi.isDuration(e))return e;if("object"==typeof e)return hi.fromObject(e);throw new c(`Unknown duration argument ${e} of type ${typeof e}`)}static fromISO(e,t){const[i]=function(e){return vt(e,[Lt,Ot])}(e);return i?hi.fromObject(i,t):hi.invalid("unparsable",`the input "${e}" can't be parsed as ISO 8601`)}static fromISOTime(e,t){const[i]=function(e){return vt(e,[Nt,ti])}(e);return i?hi.fromObject(i,t):hi.invalid("unparsable",`the input "${e}" can't be parsed as ISO 8601`)}static invalid(e,t=null){if(!e)throw new c("need to specify a reason the Duration is invalid");const i=e instanceof he?e:new he(e,t);if(de.throwOnInvalid)throw new n(i);return new hi({invalid:i})}static normalizeUnit(e){const t={year:"years",years:"years",quarter:"quarters",quarters:"quarters",month:"months",months:"months",week:"weeks",weeks:"weeks",day:"days",days:"days",hour:"hours",hours:"hours",minute:"minutes",minutes:"minutes",second:"seconds",seconds:"seconds",millisecond:"milliseconds",milliseconds:"milliseconds"}[e?e.toLowerCase():e];if(!t)throw new a(e);return t}static isDuration(e){return e&&e.isLuxonDuration||!1}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}toFormat(e,t={}){const i={...t,floor:!1!==t.round&&!1!==t.floor};return this.isValid?ft.create(this.loc,i).formatDurationFromString(this,e):ni}toHuman(e={}){if(!this.isValid)return ni;const t=li.map((t=>{const i=this.values[t];return De(i)?null:this.loc.numberFormatter({style:"unit",unitDisplay:"long",...e,unit:t.slice(0,-1)}).format(i)})).filter((e=>e));return this.loc.listFormatter({type:"conjunction",style:e.listStyle||"narrow",...e}).format(t)}toObject(){return this.isValid?{...this.values}:{}}toISO(){if(!this.isValid)return null;let e="P";return 0!==this.years&&(e+=this.years+"Y"),0===this.months&&0===this.quarters||(e+=this.months+3*this.quarters+"M"),0!==this.weeks&&(e+=this.weeks+"W"),0!==this.days&&(e+=this.days+"D"),0===this.hours&&0===this.minutes&&0===this.seconds&&0===this.milliseconds||(e+="T"),0!==this.hours&&(e+=this.hours+"H"),0!==this.minutes&&(e+=this.minutes+"M"),0===this.seconds&&0===this.milliseconds||(e+=Ve(this.seconds+this.milliseconds/1e3,3)+"S"),"P"===e&&(e+="T0S"),e}toISOTime(e={}){if(!this.isValid)return null;const t=this.toMillis();return t<0||t>=864e5?null:(e={suppressMilliseconds:!1,suppressSeconds:!1,includePrefix:!1,format:"extended",...e,includeOffset:!1},os.fromMillis(t,{zone:"UTC"}).toISOTime(e))}toJSON(){return this.toISO()}toString(){return this.toISO()}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Duration { values: ${JSON.stringify(this.values)} }`:`Duration { Invalid, reason: ${this.invalidReason} }`}toMillis(){return this.isValid?ui(this.matrix,this.values):NaN}valueOf(){return this.toMillis()}plus(e){if(!this.isValid)return this;const t=hi.fromDurationLike(e),i={};for(const e of li)(Ne(t.values,e)||Ne(this.values,e))&&(i[e]=t.get(e)+this.get(e));return Ai(this,{values:i},!0)}minus(e){if(!this.isValid)return this;const t=hi.fromDurationLike(e);return this.plus(t.negate())}mapUnits(e){if(!this.isValid)return this;const t={};for(const i of Object.keys(this.values))t[i]=Ke(e(this.values[i],i));return Ai(this,{values:t},!0)}get(e){return this[hi.normalizeUnit(e)]}set(e){return this.isValid?Ai(this,{values:{...this.values,...Ze(e,hi.normalizeUnit)}}):this}reconfigure({locale:e,numberingSystem:t,conversionAccuracy:i,matrix:s}={}){return Ai(this,{loc:this.loc.clone({locale:e,numberingSystem:t}),matrix:s,conversionAccuracy:i})}as(e){return this.isValid?this.shiftTo(e).get(e):NaN}normalize(){if(!this.isValid)return this;const e=this.toObject();return di(this.matrix,e),Ai(this,{values:e},!0)}rescale(){return this.isValid?Ai(this,{values:function(e){const t={};for(const[i,s]of Object.entries(e))0!==s&&(t[i]=s);return t}(this.normalize().shiftToAll().toObject())},!0):this}shiftTo(...e){if(!this.isValid)return this;if(0===e.length)return this;e=e.map((e=>hi.normalizeUnit(e)));const t={},i={},s=this.toObject();let r;for(const n of li)if(e.indexOf(n)>=0){r=n;let e=0;for(const t in i)e+=this.matrix[t][n]*i[t],i[t]=0;Se(s[n])&&(e+=s[n]);const o=Math.trunc(e);t[n]=o,i[n]=(1e3*e-1e3*o)/1e3}else Se(s[n])&&(i[n]=s[n]);for(const e in i)0!==i[e]&&(t[r]+=e===r?i[e]:i[e]/this.matrix[r][e]);return di(this.matrix,t),Ai(this,{values:t},!0)}shiftToAll(){return this.isValid?this.shiftTo("years","months","weeks","days","hours","minutes","seconds","milliseconds"):this}negate(){if(!this.isValid)return this;const e={};for(const t of Object.keys(this.values))e[t]=0===this.values[t]?0:-this.values[t];return Ai(this,{values:e},!0)}get years(){return this.isValid?this.values.years||0:NaN}get quarters(){return this.isValid?this.values.quarters||0:NaN}get months(){return this.isValid?this.values.months||0:NaN}get weeks(){return this.isValid?this.values.weeks||0:NaN}get days(){return this.isValid?this.values.days||0:NaN}get hours(){return this.isValid?this.values.hours||0:NaN}get minutes(){return this.isValid?this.values.minutes||0:NaN}get seconds(){return this.isValid?this.values.seconds||0:NaN}get milliseconds(){return this.isValid?this.values.milliseconds||0:NaN}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}equals(e){if(!this.isValid||!e.isValid)return!1;if(!this.loc.equals(e.loc))return!1;for(const s of li)if(t=this.values[s],i=e.values[s],!(void 0===t||0===t?void 0===i||0===i:t===i))return!1;var t,i;return!0}}const mi="Invalid Interval";class gi{constructor(e){this.s=e.start,this.e=e.end,this.invalid=e.invalid||null,this.isLuxonInterval=!0}static invalid(e,t=null){if(!e)throw new c("need to specify a reason the Interval is invalid");const i=e instanceof he?e:new he(e,t);if(de.throwOnInvalid)throw new r(i);return new gi({invalid:i})}static fromDateTimes(e,t){const i=as(e),s=as(t),r=function(e,t){return e&&e.isValid?t&&t.isValid?te}isBefore(e){return!!this.isValid&&this.e<=e}contains(e){return!!this.isValid&&this.s<=e&&this.e>e}set({start:e,end:t}={}){return this.isValid?gi.fromDateTimes(e||this.s,t||this.e):this}splitAt(...e){if(!this.isValid)return[];const t=e.map(as).filter((e=>this.contains(e))).sort(((e,t)=>e.toMillis()-t.toMillis())),i=[];let{s}=this,r=0;for(;s+this.e?this.e:e;i.push(gi.fromDateTimes(s,n)),s=n,r+=1}return i}splitBy(e){const t=hi.fromDurationLike(e);if(!this.isValid||!t.isValid||0===t.as("milliseconds"))return[];let i,{s}=this,r=1;const n=[];for(;se*r)));i=+e>+this.e?this.e:e,n.push(gi.fromDateTimes(s,i)),s=i,r+=1}return n}divideEqually(e){return this.isValid?this.splitBy(this.length()/e).slice(0,e):[]}overlaps(e){return this.e>e.s&&this.s=e.e}equals(e){return!(!this.isValid||!e.isValid)&&this.s.equals(e.s)&&this.e.equals(e.e)}intersection(e){if(!this.isValid)return this;const t=this.s>e.s?this.s:e.s,i=this.e=i?null:gi.fromDateTimes(t,i)}union(e){if(!this.isValid)return this;const t=this.se.e?this.e:e.e;return gi.fromDateTimes(t,i)}static merge(e){const[t,i]=e.sort(((e,t)=>e.s-t.s)).reduce((([e,t],i)=>t?t.overlaps(i)||t.abutsStart(i)?[e,t.union(i)]:[e.concat([t]),i]:[e,i]),[[],null]);return i&&t.push(i),t}static xor(e){let t=null,i=0;const s=[],r=e.map((e=>[{time:e.s,type:"s"},{time:e.e,type:"e"}])),n=Array.prototype.concat(...r).sort(((e,t)=>e.time-t.time));for(const e of n)i+="s"===e.type?1:-1,1===i?t=e.time:(t&&+t!=+e.time&&s.push(gi.fromDateTimes(t,e.time)),t=null);return gi.merge(s)}difference(...e){return gi.xor([this].concat(e)).map((e=>this.intersection(e))).filter((e=>e&&!e.isEmpty()))}toString(){return this.isValid?`[${this.s.toISO()} – ${this.e.toISO()})`:mi}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Interval { start: ${this.s.toISO()}, end: ${this.e.toISO()} }`:`Interval { Invalid, reason: ${this.invalidReason} }`}toLocaleString(e=d,t={}){return this.isValid?ft.create(this.s.loc.clone(t),e).formatInterval(this):mi}toISO(e){return this.isValid?`${this.s.toISO(e)}/${this.e.toISO(e)}`:mi}toISODate(){return this.isValid?`${this.s.toISODate()}/${this.e.toISODate()}`:mi}toISOTime(e){return this.isValid?`${this.s.toISOTime(e)}/${this.e.toISOTime(e)}`:mi}toFormat(e,{separator:t=" – "}={}){return this.isValid?`${this.s.toFormat(e)}${t}${this.e.toFormat(e)}`:mi}toDuration(e,t){return this.isValid?this.e.diff(this.s,e,t):hi.invalid(this.invalidReason)}mapEndpoints(e){return gi.fromDateTimes(e(this.s),e(this.e))}}class fi{static hasDST(e=de.defaultZone){const t=os.now().setZone(e).set({month:12});return!e.isUniversal&&t.offset!==t.set({month:6}).offset}static isValidIANAZone(e){return G.isValidZone(e)}static normalizeZone(e){return re(e,de.defaultZone)}static getStartOfWeek({locale:e=null,locObj:t=null}={}){return(t||ee.create(e)).getStartOfWeek()}static getMinimumDaysInFirstWeek({locale:e=null,locObj:t=null}={}){return(t||ee.create(e)).getMinDaysInFirstWeek()}static getWeekendWeekdays({locale:e=null,locObj:t=null}={}){return(t||ee.create(e)).getWeekendDays().slice()}static months(e="long",{locale:t=null,numberingSystem:i=null,locObj:s=null,outputCalendar:r="gregory"}={}){return(s||ee.create(t,i,r)).months(e)}static monthsFormat(e="long",{locale:t=null,numberingSystem:i=null,locObj:s=null,outputCalendar:r="gregory"}={}){return(s||ee.create(t,i,r)).months(e,!0)}static weekdays(e="long",{locale:t=null,numberingSystem:i=null,locObj:s=null}={}){return(s||ee.create(t,i,null)).weekdays(e)}static weekdaysFormat(e="long",{locale:t=null,numberingSystem:i=null,locObj:s=null}={}){return(s||ee.create(t,i,null)).weekdays(e,!0)}static meridiems({locale:e=null}={}){return ee.create(e).meridiems()}static eras(e="short",{locale:t=null}={}){return ee.create(t,null,"gregory").eras(e)}static features(){return{relative:Re(),localeWeek:Te()}}}function Ei(e,t){const i=e=>e.toUTC(0,{keepLocalTime:!0}).startOf("day").valueOf(),s=i(t)-i(e);return Math.floor(hi.fromMillis(s).as("days"))}const Ci={arab:"[٠-٩]",arabext:"[۰-۹]",bali:"[᭐-᭙]",beng:"[০-৯]",deva:"[०-९]",fullwide:"[0-9]",gujr:"[૦-૯]",hanidec:"[〇|一|二|三|四|五|六|七|八|九]",khmr:"[០-៩]",knda:"[೦-೯]",laoo:"[໐-໙]",limb:"[᥆-᥏]",mlym:"[൦-൯]",mong:"[᠐-᠙]",mymr:"[၀-၉]",orya:"[୦-୯]",tamldec:"[௦-௯]",telu:"[౦-౯]",thai:"[๐-๙]",tibt:"[༠-༩]",latn:"\\d"},yi={arab:[1632,1641],arabext:[1776,1785],bali:[6992,7001],beng:[2534,2543],deva:[2406,2415],fullwide:[65296,65303],gujr:[2790,2799],khmr:[6112,6121],knda:[3302,3311],laoo:[3792,3801],limb:[6470,6479],mlym:[3430,3439],mong:[6160,6169],mymr:[4160,4169],orya:[2918,2927],tamldec:[3046,3055],telu:[3174,3183],thai:[3664,3673],tibt:[3872,3881]},vi=Ci.hanidec.replace(/[\[|\]]/g,"").split("");function Ii({numberingSystem:e},t=""){return new RegExp(`${Ci[e||"latn"]}${t}`)}function Bi(e,t=(e=>e)){return{regex:e,deser:([e])=>t(function(e){let t=parseInt(e,10);if(isNaN(t)){t="";for(let i=0;i=i&&s<=r&&(t+=s-i)}}return parseInt(t,10)}return t}(e))}}const wi=`[ ${String.fromCharCode(160)}]`,bi=new RegExp(wi,"g");function Qi(e){return e.replace(/\./g,"\\.?").replace(bi,wi)}function xi(e){return e.replace(/\./g,"").replace(bi," ").toLowerCase()}function ki(e,t){return null===e?null:{regex:RegExp(e.map(Qi).join("|")),deser:([i])=>e.findIndex((e=>xi(i)===xi(e)))+t}}function Di(e,t){return{regex:e,deser:([,e,t])=>Xe(e,t),groups:t}}function Si(e){return{regex:e,deser:([e])=>e}}const _i={year:{"2-digit":"yy",numeric:"yyyyy"},month:{numeric:"M","2-digit":"MM",short:"MMM",long:"MMMM"},day:{numeric:"d","2-digit":"dd"},weekday:{short:"EEE",long:"EEEE"},dayperiod:"a",dayPeriod:"a",hour12:{numeric:"h","2-digit":"hh"},hour24:{numeric:"H","2-digit":"HH"},minute:{numeric:"m","2-digit":"mm"},second:{numeric:"s","2-digit":"ss"},timeZoneName:{long:"ZZZZZ",short:"ZZZ"}};let Ri=null;function Ti(e,t){return Array.prototype.concat(...e.map((e=>function(e,t){if(e.literal)return e;const i=Ni(ft.macroTokenToFormatOpts(e.val),t);return null==i||i.includes(void 0)?e:i}(e,t))))}function Fi(e,t,i){const s=Ti(ft.parseFormat(i),e),r=s.map((t=>function(e,t){const i=Ii(t),s=Ii(t,"{2}"),r=Ii(t,"{3}"),n=Ii(t,"{4}"),o=Ii(t,"{6}"),a=Ii(t,"{1,2}"),c=Ii(t,"{1,3}"),l=Ii(t,"{1,6}"),p=Ii(t,"{1,9}"),A=Ii(t,"{2,4}"),u=Ii(t,"{4,6}"),d=e=>{return{regex:RegExp((t=e.val,t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"))),deser:([e])=>e,literal:!0};var t},h=(h=>{if(e.literal)return d(h);switch(h.val){case"G":return ki(t.eras("short"),0);case"GG":return ki(t.eras("long"),0);case"y":return Bi(l);case"yy":case"kk":return Bi(A,ze);case"yyyy":case"kkkk":return Bi(n);case"yyyyy":return Bi(u);case"yyyyyy":return Bi(o);case"M":case"L":case"d":case"H":case"h":case"m":case"q":case"s":case"W":return Bi(a);case"MM":case"LL":case"dd":case"HH":case"hh":case"mm":case"qq":case"ss":case"WW":return Bi(s);case"MMM":return ki(t.months("short",!0),1);case"MMMM":return ki(t.months("long",!0),1);case"LLL":return ki(t.months("short",!1),1);case"LLLL":return ki(t.months("long",!1),1);case"o":case"S":return Bi(c);case"ooo":case"SSS":return Bi(r);case"u":return Si(p);case"uu":return Si(a);case"uuu":case"E":case"c":return Bi(i);case"a":return ki(t.meridiems(),0);case"EEE":return ki(t.weekdays("short",!1),1);case"EEEE":return ki(t.weekdays("long",!1),1);case"ccc":return ki(t.weekdays("short",!0),1);case"cccc":return ki(t.weekdays("long",!0),1);case"Z":case"ZZ":return Di(new RegExp(`([+-]${a.source})(?::(${s.source}))?`),2);case"ZZZ":return Di(new RegExp(`([+-]${a.source})(${s.source})?`),2);case"z":return Si(/[a-z_+-/]{1,256}?/i);case" ":return Si(/[^\S\n\r]/);default:return d(h)}})(e)||{invalidReason:"missing Intl.DateTimeFormat.formatToParts support"};return h.token=e,h}(t,e))),n=r.find((e=>e.invalidReason));if(n)return{input:t,tokens:s,invalidReason:n.invalidReason};{const[e,i]=function(e){return[`^${e.map((e=>e.regex)).reduce(((e,t)=>`${e}(${t.source})`),"")}$`,e]}(r),n=RegExp(e,"i"),[a,c]=function(e,t,i){const s=e.match(t);if(s){const e={};let t=1;for(const r in i)if(Ne(i,r)){const n=i[r],o=n.groups?n.groups+1:1;!n.literal&&n.token&&(e[n.token.val[0]]=n.deser(s.slice(t,t+o))),t+=o}return[s,e]}return[s,{}]}(t,n,i),[l,p,A]=c?function(e){let t,i=null;return De(e.z)||(i=G.create(e.z)),De(e.Z)||(i||(i=new ie(e.Z)),t=e.Z),De(e.q)||(e.M=3*(e.q-1)+1),De(e.h)||(e.h<12&&1===e.a?e.h+=12:12===e.h&&0===e.a&&(e.h=0)),0===e.G&&e.y&&(e.y=-e.y),De(e.u)||(e.S=Ge(e.u)),[Object.keys(e).reduce(((t,i)=>{const s=(e=>{switch(e){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":case"H":return"hour";case"d":return"day";case"o":return"ordinal";case"L":case"M":return"month";case"y":return"year";case"E":case"c":return"weekday";case"W":return"weekNumber";case"k":return"weekYear";case"q":return"quarter";default:return null}})(i);return s&&(t[s]=e[i]),t}),{}),i,t]}(c):[null,null,void 0];if(Ne(c,"a")&&Ne(c,"H"))throw new o("Can't include meridiem when specifying 24-hour format");return{input:t,tokens:s,regex:n,rawMatches:a,matches:c,result:l,zone:p,specificOffset:A}}}function Ni(e,t){if(!e)return null;const i=ft.create(t,e).dtFormatter((Ri||(Ri=os.fromMillis(1555555555555)),Ri)),s=i.formatToParts(),r=i.resolvedOptions();return s.map((t=>function(e,t,i){const{type:s,value:r}=e;if("literal"===s){const e=/^\s+$/.test(r);return{literal:!e,val:e?" ":r}}const n=t[s];let o=s;"hour"===s&&(o=null!=t.hour12?t.hour12?"hour12":"hour24":null!=t.hourCycle?"h11"===t.hourCycle||"h12"===t.hourCycle?"hour12":"hour24":i.hour12?"hour12":"hour24");let a=_i[o];if("object"==typeof a&&(a=a[n]),a)return{literal:!1,val:a}}(t,e,r)))}const Li="Invalid DateTime",Oi=864e13;function Mi(e){return new he("unsupported zone",`the zone "${e.name}" is not supported`)}function Ui(e){return null===e.weekData&&(e.weekData=Ie(e.c)),e.weekData}function Pi(e){return null===e.localWeekData&&(e.localWeekData=Ie(e.c,e.loc.getMinDaysInFirstWeek(),e.loc.getStartOfWeek())),e.localWeekData}function Gi(e,t){const i={ts:e.ts,zone:e.zone,c:e.c,o:e.o,loc:e.loc,invalid:e.invalid};return new os({...i,...t,old:i})}function Vi(e,t,i){let s=e-60*t*1e3;const r=i.offset(s);if(t===r)return[s,t];s-=60*(r-t)*1e3;const n=i.offset(s);return r===n?[s,r]:[e-60*Math.min(r,n)*1e3,Math.max(r,n)]}function ji(e,t){const i=new Date(e+=60*t*1e3);return{year:i.getUTCFullYear(),month:i.getUTCMonth()+1,day:i.getUTCDate(),hour:i.getUTCHours(),minute:i.getUTCMinutes(),second:i.getUTCSeconds(),millisecond:i.getUTCMilliseconds()}}function Hi(e,t,i){return Vi(qe(e),t,i)}function Ji(e,t){const i=e.o,s=e.c.year+Math.trunc(t.years),r=e.c.month+Math.trunc(t.months)+3*Math.trunc(t.quarters),n={...e.c,year:s,month:r,day:Math.min(e.c.day,Je(s,r))+Math.trunc(t.days)+7*Math.trunc(t.weeks)},o=hi.fromObject({years:t.years-Math.trunc(t.years),quarters:t.quarters-Math.trunc(t.quarters),months:t.months-Math.trunc(t.months),weeks:t.weeks-Math.trunc(t.weeks),days:t.days-Math.trunc(t.days),hours:t.hours,minutes:t.minutes,seconds:t.seconds,milliseconds:t.milliseconds}).as("milliseconds"),a=qe(n);let[c,l]=Vi(a,i,e.zone);return 0!==o&&(c+=o,l=e.zone.offset(c)),{ts:c,o:l}}function qi(e,t,i,s,r,n){const{setZone:o,zone:a}=i;if(e&&0!==Object.keys(e).length||t){const s=t||a,r=os.fromObject(e,{...i,zone:s,specificOffset:n});return o?r:r.setZone(a)}return os.invalid(new he("unparsable",`the input "${r}" can't be parsed as ${s}`))}function Yi(e,t,i=!0){return e.isValid?ft.create(ee.create("en-US"),{allowZ:i,forceSimple:!0}).formatDateTimeFromString(e,t):null}function Wi(e,t){const i=e.c.year>9999||e.c.year<0;let s="";return i&&e.c.year>=0&&(s+="+"),s+=Me(e.c.year,i?6:4),t?(s+="-",s+=Me(e.c.month),s+="-",s+=Me(e.c.day)):(s+=Me(e.c.month),s+=Me(e.c.day)),s}function zi(e,t,i,s,r,n){let o=Me(e.c.hour);return t?(o+=":",o+=Me(e.c.minute),0===e.c.millisecond&&0===e.c.second&&i||(o+=":")):o+=Me(e.c.minute),0===e.c.millisecond&&0===e.c.second&&i||(o+=Me(e.c.second),0===e.c.millisecond&&s||(o+=".",o+=Me(e.c.millisecond,3))),r&&(e.isOffsetFixed&&0===e.offset&&!n?o+="Z":e.o<0?(o+="-",o+=Me(Math.trunc(-e.o/60)),o+=":",o+=Me(Math.trunc(-e.o%60))):(o+="+",o+=Me(Math.trunc(e.o/60)),o+=":",o+=Me(Math.trunc(e.o%60)))),n&&(o+="["+e.zone.ianaName+"]"),o}const $i={month:1,day:1,hour:0,minute:0,second:0,millisecond:0},Xi={weekNumber:1,weekday:1,hour:0,minute:0,second:0,millisecond:0},Ki={ordinal:1,hour:0,minute:0,second:0,millisecond:0},Zi=["year","month","day","hour","minute","second","millisecond"],es=["weekYear","weekNumber","weekday","hour","minute","second","millisecond"],ts=["year","ordinal","hour","minute","second","millisecond"];function is(e){switch(e.toLowerCase()){case"localweekday":case"localweekdays":return"localWeekday";case"localweeknumber":case"localweeknumbers":return"localWeekNumber";case"localweekyear":case"localweekyears":return"localWeekYear";default:return function(e){const t={year:"year",years:"year",month:"month",months:"month",day:"day",days:"day",hour:"hour",hours:"hour",minute:"minute",minutes:"minute",quarter:"quarter",quarters:"quarter",second:"second",seconds:"second",millisecond:"millisecond",milliseconds:"millisecond",weekday:"weekday",weekdays:"weekday",weeknumber:"weekNumber",weeksnumber:"weekNumber",weeknumbers:"weekNumber",weekyear:"weekYear",weekyears:"weekYear",ordinal:"ordinal"}[e.toLowerCase()];if(!t)throw new a(e);return t}(e)}}function ss(e,t){const i=re(t.zone,de.defaultZone),s=ee.fromObject(t),r=de.now();let n,o;if(De(e.year))n=r;else{for(const t of Zi)De(e[t])&&(e[t]=$i[t]);const t=xe(e)||ke(e);if(t)return os.invalid(t);const s=i.offset(r);[n,o]=Hi(e,s,i)}return new os({ts:n,zone:i,loc:s,o})}function rs(e,t,i){const s=!!De(i.round)||i.round,r=(e,r)=>(e=Ve(e,s||i.calendary?0:2,!0),t.loc.clone(i).relFormatter(i).format(e,r)),n=s=>i.calendary?t.hasSame(e,s)?0:t.startOf(s).diff(e.startOf(s),s).get(s):t.diff(e,s).get(s);if(i.unit)return r(n(i.unit),i.unit);for(const e of i.units){const t=n(e);if(Math.abs(t)>=1)return r(t,e)}return r(e>t?-0:0,i.units[i.units.length-1])}function ns(e){let t,i={};return e.length>0&&"object"==typeof e[e.length-1]?(i=e[e.length-1],t=Array.from(e).slice(0,e.length-1)):t=Array.from(e),[i,t]}class os{constructor(e){const t=e.zone||de.defaultZone;let i=e.invalid||(Number.isNaN(e.ts)?new he("invalid input"):null)||(t.isValid?null:Mi(t));this.ts=De(e.ts)?de.now():e.ts;let s=null,r=null;if(!i)if(e.old&&e.old.ts===this.ts&&e.old.zone.equals(t))[s,r]=[e.old.c,e.old.o];else{const e=t.offset(this.ts);s=ji(this.ts,e),i=Number.isNaN(s.year)?new he("invalid input"):null,s=i?null:s,r=i?null:e}this._zone=t,this.loc=e.loc||ee.create(),this.invalid=i,this.weekData=null,this.localWeekData=null,this.c=s,this.o=r,this.isLuxonDateTime=!0}static now(){return new os({})}static local(){const[e,t]=ns(arguments),[i,s,r,n,o,a,c]=t;return ss({year:i,month:s,day:r,hour:n,minute:o,second:a,millisecond:c},e)}static utc(){const[e,t]=ns(arguments),[i,s,r,n,o,a,c]=t;return e.zone=ie.utcInstance,ss({year:i,month:s,day:r,hour:n,minute:o,second:a,millisecond:c},e)}static fromJSDate(e,t={}){const i=(s=e,"[object Date]"===Object.prototype.toString.call(s)?e.valueOf():NaN);var s;if(Number.isNaN(i))return os.invalid("invalid input");const r=re(t.zone,de.defaultZone);return r.isValid?new os({ts:i,zone:r,loc:ee.fromObject(t)}):os.invalid(Mi(r))}static fromMillis(e,t={}){if(Se(e))return e<-Oi||e>Oi?os.invalid("Timestamp out of range"):new os({ts:e,zone:re(t.zone,de.defaultZone),loc:ee.fromObject(t)});throw new c(`fromMillis requires a numerical input, but received a ${typeof e} with value ${e}`)}static fromSeconds(e,t={}){if(Se(e))return new os({ts:1e3*e,zone:re(t.zone,de.defaultZone),loc:ee.fromObject(t)});throw new c("fromSeconds requires a numerical input")}static fromObject(e,t={}){e=e||{};const i=re(t.zone,de.defaultZone);if(!i.isValid)return os.invalid(Mi(i));const s=ee.fromObject(t),r=Ze(e,is),{minDaysInFirstWeek:n,startOfWeek:a}=Qe(r,s),c=de.now(),l=De(t.specificOffset)?i.offset(c):t.specificOffset,p=!De(r.ordinal),A=!De(r.year),u=!De(r.month)||!De(r.day),d=A||u,h=r.weekYear||r.weekNumber;if((d||p)&&h)throw new o("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(u&&p)throw new o("Can't mix ordinal dates with month/day");const m=h||r.weekday&&!d;let g,f,E=ji(c,l);m?(g=es,f=Xi,E=Ie(E,n,a)):p?(g=ts,f=Ki,E=we(E)):(g=Zi,f=$i);let C=!1;for(const e of g)De(r[e])?r[e]=C?f[e]:E[e]:C=!0;const y=m?function(e,t=4,i=1){const s=_e(e.weekYear),r=Oe(e.weekNumber,1,We(e.weekYear,t,i)),n=Oe(e.weekday,1,7);return s?r?!n&&fe("weekday",e.weekday):fe("week",e.weekNumber):fe("weekYear",e.weekYear)}(r,n,a):p?function(e){const t=_e(e.year),i=Oe(e.ordinal,1,He(e.year));return t?!i&&fe("ordinal",e.ordinal):fe("year",e.year)}(r):xe(r),v=y||ke(r);if(v)return os.invalid(v);const I=m?Be(r,n,a):p?be(r):r,[B,w]=Hi(I,l,i),b=new os({ts:B,zone:i,o:w,loc:s});return r.weekday&&d&&e.weekday!==b.weekday?os.invalid("mismatched weekday",`you can't specify both a weekday of ${r.weekday} and a date of ${b.toISO()}`):b}static fromISO(e,t={}){const[i,s]=function(e){return vt(e,[Yt,Xt],[Wt,Kt],[zt,Zt],[$t,ei])}(e);return qi(i,s,t,"ISO 8601",e)}static fromRFC2822(e,t={}){const[i,s]=function(e){return vt(function(e){return e.replace(/\([^()]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").trim()}(e),[Pt,Gt])}(e);return qi(i,s,t,"RFC 2822",e)}static fromHTTP(e,t={}){const[i,s]=function(e){return vt(e,[Vt,Jt],[jt,Jt],[Ht,qt])}(e);return qi(i,s,t,"HTTP",t)}static fromFormat(e,t,i={}){if(De(e)||De(t))throw new c("fromFormat requires an input string and a format");const{locale:s=null,numberingSystem:r=null}=i,n=ee.fromOpts({locale:s,numberingSystem:r,defaultToEN:!0}),[o,a,l,p]=function(e,t,i){const{result:s,zone:r,specificOffset:n,invalidReason:o}=Fi(e,t,i);return[s,r,n,o]}(n,e,t);return p?os.invalid(p):qi(o,a,i,`format ${t}`,e,l)}static fromString(e,t,i={}){return os.fromFormat(e,t,i)}static fromSQL(e,t={}){const[i,s]=function(e){return vt(e,[ii,Xt],[si,ri])}(e);return qi(i,s,t,"SQL",e)}static invalid(e,t=null){if(!e)throw new c("need to specify a reason the DateTime is invalid");const i=e instanceof he?e:new he(e,t);if(de.throwOnInvalid)throw new s(i);return new os({invalid:i})}static isDateTime(e){return e&&e.isLuxonDateTime||!1}static parseFormatForOpts(e,t={}){const i=Ni(e,ee.fromObject(t));return i?i.map((e=>e?e.val:null)).join(""):null}static expandFormat(e,t={}){return Ti(ft.parseFormat(e),ee.fromObject(t)).map((e=>e.val)).join("")}get(e){return this[e]}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}get outputCalendar(){return this.isValid?this.loc.outputCalendar:null}get zone(){return this._zone}get zoneName(){return this.isValid?this.zone.name:null}get year(){return this.isValid?this.c.year:NaN}get quarter(){return this.isValid?Math.ceil(this.c.month/3):NaN}get month(){return this.isValid?this.c.month:NaN}get day(){return this.isValid?this.c.day:NaN}get hour(){return this.isValid?this.c.hour:NaN}get minute(){return this.isValid?this.c.minute:NaN}get second(){return this.isValid?this.c.second:NaN}get millisecond(){return this.isValid?this.c.millisecond:NaN}get weekYear(){return this.isValid?Ui(this).weekYear:NaN}get weekNumber(){return this.isValid?Ui(this).weekNumber:NaN}get weekday(){return this.isValid?Ui(this).weekday:NaN}get isWeekend(){return this.isValid&&this.loc.getWeekendDays().includes(this.weekday)}get localWeekday(){return this.isValid?Pi(this).weekday:NaN}get localWeekNumber(){return this.isValid?Pi(this).weekNumber:NaN}get localWeekYear(){return this.isValid?Pi(this).weekYear:NaN}get ordinal(){return this.isValid?we(this.c).ordinal:NaN}get monthShort(){return this.isValid?fi.months("short",{locObj:this.loc})[this.month-1]:null}get monthLong(){return this.isValid?fi.months("long",{locObj:this.loc})[this.month-1]:null}get weekdayShort(){return this.isValid?fi.weekdays("short",{locObj:this.loc})[this.weekday-1]:null}get weekdayLong(){return this.isValid?fi.weekdays("long",{locObj:this.loc})[this.weekday-1]:null}get offset(){return this.isValid?+this.o:NaN}get offsetNameShort(){return this.isValid?this.zone.offsetName(this.ts,{format:"short",locale:this.locale}):null}get offsetNameLong(){return this.isValid?this.zone.offsetName(this.ts,{format:"long",locale:this.locale}):null}get isOffsetFixed(){return this.isValid?this.zone.isUniversal:null}get isInDST(){return!this.isOffsetFixed&&(this.offset>this.set({month:1,day:1}).offset||this.offset>this.set({month:5}).offset)}getPossibleOffsets(){if(!this.isValid||this.isOffsetFixed)return[this];const e=864e5,t=6e4,i=qe(this.c),s=this.zone.offset(i-e),r=this.zone.offset(i+e),n=this.zone.offset(i-s*t),o=this.zone.offset(i-r*t);if(n===o)return[this];const a=i-n*t,c=i-o*t,l=ji(a,n),p=ji(c,o);return l.hour===p.hour&&l.minute===p.minute&&l.second===p.second&&l.millisecond===p.millisecond?[Gi(this,{ts:a}),Gi(this,{ts:c})]:[this]}get isInLeapYear(){return je(this.year)}get daysInMonth(){return Je(this.year,this.month)}get daysInYear(){return this.isValid?He(this.year):NaN}get weeksInWeekYear(){return this.isValid?We(this.weekYear):NaN}get weeksInLocalWeekYear(){return this.isValid?We(this.localWeekYear,this.loc.getMinDaysInFirstWeek(),this.loc.getStartOfWeek()):NaN}resolvedLocaleOptions(e={}){const{locale:t,numberingSystem:i,calendar:s}=ft.create(this.loc.clone(e),e).resolvedOptions(this);return{locale:t,numberingSystem:i,outputCalendar:s}}toUTC(e=0,t={}){return this.setZone(ie.instance(e),t)}toLocal(){return this.setZone(de.defaultZone)}setZone(e,{keepLocalTime:t=!1,keepCalendarTime:i=!1}={}){if((e=re(e,de.defaultZone)).equals(this.zone))return this;if(e.isValid){let s=this.ts;if(t||i){const t=e.offset(this.ts),i=this.toObject();[s]=Hi(i,t,e)}return Gi(this,{ts:s,zone:e})}return os.invalid(Mi(e))}reconfigure({locale:e,numberingSystem:t,outputCalendar:i}={}){return Gi(this,{loc:this.loc.clone({locale:e,numberingSystem:t,outputCalendar:i})})}setLocale(e){return this.reconfigure({locale:e})}set(e){if(!this.isValid)return this;const t=Ze(e,is),{minDaysInFirstWeek:i,startOfWeek:s}=Qe(t,this.loc),r=!De(t.weekYear)||!De(t.weekNumber)||!De(t.weekday),n=!De(t.ordinal),a=!De(t.year),c=!De(t.month)||!De(t.day),l=a||c,p=t.weekYear||t.weekNumber;if((l||n)&&p)throw new o("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(c&&n)throw new o("Can't mix ordinal dates with month/day");let A;r?A=Be({...Ie(this.c,i,s),...t},i,s):De(t.ordinal)?(A={...this.toObject(),...t},De(t.day)&&(A.day=Math.min(Je(A.year,A.month),A.day))):A=be({...we(this.c),...t});const[u,d]=Hi(A,this.o,this.zone);return Gi(this,{ts:u,o:d})}plus(e){return this.isValid?Gi(this,Ji(this,hi.fromDurationLike(e))):this}minus(e){return this.isValid?Gi(this,Ji(this,hi.fromDurationLike(e).negate())):this}startOf(e,{useLocaleWeeks:t=!1}={}){if(!this.isValid)return this;const i={},s=hi.normalizeUnit(e);switch(s){case"years":i.month=1;case"quarters":case"months":i.day=1;case"weeks":case"days":i.hour=0;case"hours":i.minute=0;case"minutes":i.second=0;case"seconds":i.millisecond=0}if("weeks"===s)if(t){const e=this.loc.getStartOfWeek(),{weekday:t}=this;tthis.valueOf(),o=function(e,t,i,s){let[r,n,o,a]=function(e,t,i){const s=[["years",(e,t)=>t.year-e.year],["quarters",(e,t)=>t.quarter-e.quarter+4*(t.year-e.year)],["months",(e,t)=>t.month-e.month+12*(t.year-e.year)],["weeks",(e,t)=>{const i=Ei(e,t);return(i-i%7)/7}],["days",Ei]],r={},n=e;let o,a;for(const[c,l]of s)i.indexOf(c)>=0&&(o=c,r[c]=l(e,t),a=n.plus(r),a>t?(r[c]--,(e=n.plus(r))>t&&(a=e,r[c]--,e=n.plus(r))):e=a);return[e,r,a,o]}(e,t,i);const c=t-r,l=i.filter((e=>["hours","minutes","seconds","milliseconds"].indexOf(e)>=0));0===l.length&&(o0?hi.fromMillis(c,s).shiftTo(...l).plus(p):p}(n?this:e,n?e:this,r,s);var a;return n?o.negate():o}diffNow(e="milliseconds",t={}){return this.diff(os.now(),e,t)}until(e){return this.isValid?gi.fromDateTimes(this,e):this}hasSame(e,t,i){if(!this.isValid)return!1;const s=e.valueOf(),r=this.setZone(e.zone,{keepLocalTime:!0});return r.startOf(t,i)<=s&&s<=r.endOf(t,i)}equals(e){return this.isValid&&e.isValid&&this.valueOf()===e.valueOf()&&this.zone.equals(e.zone)&&this.loc.equals(e.loc)}toRelative(e={}){if(!this.isValid)return null;const t=e.base||os.fromObject({},{zone:this.zone}),i=e.padding?thise.valueOf()),Math.min)}static max(...e){if(!e.every(os.isDateTime))throw new c("max requires all arguments be DateTimes");return Fe(e,(e=>e.valueOf()),Math.max)}static fromFormatExplain(e,t,i={}){const{locale:s=null,numberingSystem:r=null}=i;return Fi(ee.fromOpts({locale:s,numberingSystem:r,defaultToEN:!0}),e,t)}static fromStringExplain(e,t,i={}){return os.fromFormatExplain(e,t,i)}static get DATE_SHORT(){return d}static get DATE_MED(){return h}static get DATE_MED_WITH_WEEKDAY(){return m}static get DATE_FULL(){return g}static get DATE_HUGE(){return f}static get TIME_SIMPLE(){return E}static get TIME_WITH_SECONDS(){return C}static get TIME_WITH_SHORT_OFFSET(){return y}static get TIME_WITH_LONG_OFFSET(){return v}static get TIME_24_SIMPLE(){return I}static get TIME_24_WITH_SECONDS(){return B}static get TIME_24_WITH_SHORT_OFFSET(){return w}static get TIME_24_WITH_LONG_OFFSET(){return b}static get DATETIME_SHORT(){return Q}static get DATETIME_SHORT_WITH_SECONDS(){return x}static get DATETIME_MED(){return k}static get DATETIME_MED_WITH_SECONDS(){return D}static get DATETIME_MED_WITH_WEEKDAY(){return S}static get DATETIME_FULL(){return _}static get DATETIME_FULL_WITH_SECONDS(){return R}static get DATETIME_HUGE(){return T}static get DATETIME_HUGE_WITH_SECONDS(){return F}}function as(e){if(os.isDateTime(e))return e;if(e&&e.valueOf&&Se(e.valueOf()))return os.fromJSDate(e);if(e&&"object"==typeof e)return os.fromObject(e);throw new c(`Unknown datetime argument: ${e}, of type ${typeof e}`)}t.DateTime=os,t.Duration=hi,t.FixedOffsetZone=ie,t.IANAZone=G,t.Info=fi,t.Interval=gi,t.InvalidZone=se,t.Settings=de,t.SystemZone=O,t.VERSION="3.4.4",t.Zone=N},10257:(e,t,i)=>{e.exports=i(66450)},69335:(e,t,i)=>{"use strict";var s,r,n,o=i(10257),a=i(71017).extname,c=/^\s*([^;\s]*)(?:;|\s|$)/,l=/^text\//i;function p(e){if(!e||"string"!=typeof e)return!1;var t=c.exec(e),i=t&&o[t[1].toLowerCase()];return i&&i.charset?i.charset:!(!t||!l.test(t[1]))&&"UTF-8"}t.charset=p,t.charsets={lookup:p},t.contentType=function(e){if(!e||"string"!=typeof e)return!1;var i=-1===e.indexOf("/")?t.lookup(e):e;if(!i)return!1;if(-1===i.indexOf("charset")){var s=t.charset(i);s&&(i+="; charset="+s.toLowerCase())}return i},t.extension=function(e){if(!e||"string"!=typeof e)return!1;var i=c.exec(e),s=i&&t.extensions[i[1].toLowerCase()];return!(!s||!s.length)&&s[0]},t.extensions=Object.create(null),t.lookup=function(e){if(!e||"string"!=typeof e)return!1;var i=a("x."+e).toLowerCase().substr(1);return i&&t.types[i]||!1},t.types=Object.create(null),s=t.extensions,r=t.types,n=["nginx","apache",void 0,"iana"],Object.keys(o).forEach((function(e){var t=o[e],i=t.extensions;if(i&&i.length){s[e]=i;for(var a=0;ap||l===p&&"application/"===r[c].substr(0,12)))continue}r[c]=e}}}))},70474:e=>{"use strict";const t=(e,t)=>{for(const i of Reflect.ownKeys(t))Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(t,i));return e};e.exports=t,e.exports.default=t},44247:e=>{var t=1e3,i=60*t,s=60*i,r=24*s;function n(e,t,i,s){var r=t>=1.5*i;return Math.round(e/i)+" "+s+(r?"s":"")}e.exports=function(e,o){o=o||{};var a,c,l=typeof e;if("string"===l&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var n=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(n){var o=parseFloat(n[1]);switch((n[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*o;case"weeks":case"week":case"w":return 6048e5*o;case"days":case"day":case"d":return o*r;case"hours":case"hour":case"hrs":case"hr":case"h":return o*s;case"minutes":case"minute":case"mins":case"min":case"m":return o*i;case"seconds":case"second":case"secs":case"sec":case"s":return o*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return o;default:return}}}}(e);if("number"===l&&isFinite(e))return o.long?(a=e,(c=Math.abs(a))>=r?n(a,c,r,"day"):c>=s?n(a,c,s,"hour"):c>=i?n(a,c,i,"minute"):c>=t?n(a,c,t,"second"):a+" ms"):function(e){var n=Math.abs(e);return n>=r?Math.round(e/r)+"d":n>=s?Math.round(e/s)+"h":n>=i?Math.round(e/i)+"m":n>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},83733:(e,t,i)=>{var s=i(12781);function r(e){s.apply(this),e=e||{},this.writable=this.readable=!0,this.muted=!1,this.on("pipe",this._onpipe),this.replace=e.replace,this._prompt=e.prompt||null,this._hadControl=!1}function n(e){return function(){var t=this._dest,i=this._src;t&&t[e]&&t[e].apply(t,arguments),i&&i[e]&&i[e].apply(i,arguments)}}e.exports=r,r.prototype=Object.create(s.prototype),Object.defineProperty(r.prototype,"constructor",{value:r,enumerable:!1}),r.prototype.mute=function(){this.muted=!0},r.prototype.unmute=function(){this.muted=!1},Object.defineProperty(r.prototype,"_onpipe",{value:function(e){this._src=e},enumerable:!1,writable:!0,configurable:!0}),Object.defineProperty(r.prototype,"isTTY",{get:function(){return this._dest?this._dest.isTTY:!!this._src&&this._src.isTTY},set:function(e){Object.defineProperty(this,"isTTY",{value:e,enumerable:!0,writable:!0,configurable:!0})},enumerable:!0,configurable:!0}),Object.defineProperty(r.prototype,"rows",{get:function(){return this._dest?this._dest.rows:this._src?this._src.rows:void 0},enumerable:!0,configurable:!0}),Object.defineProperty(r.prototype,"columns",{get:function(){return this._dest?this._dest.columns:this._src?this._src.columns:void 0},enumerable:!0,configurable:!0}),r.prototype.pipe=function(e,t){return this._dest=e,s.prototype.pipe.call(this,e,t)},r.prototype.pause=function(){if(this._src)return this._src.pause()},r.prototype.resume=function(){if(this._src)return this._src.resume()},r.prototype.write=function(e){if(this.muted){if(!this.replace)return!0;if(e.match(/^\u001b/))return 0===e.indexOf(this._prompt)&&(e=(e=e.substr(this._prompt.length)).replace(/./g,this.replace),e=this._prompt+e),this._hadControl=!0,this.emit("data",e);this._prompt&&this._hadControl&&0===e.indexOf(this._prompt)&&(this._hadControl=!1,this.emit("data",this._prompt),e=e.substr(this._prompt.length)),e=e.toString().replace(/./g,this.replace)}this.emit("data",e)},r.prototype.end=function(e){this.muted&&(e=e&&this.replace?e.toString().replace(/./g,this.replace):null),e&&this.emit("data",e),this.emit("end")},r.prototype.destroy=n("destroy"),r.prototype.destroySoon=n("destroySoon"),r.prototype.close=n("close")},39470:(e,t,i)=>{"use strict";i.r(t),i.d(t,{App:()=>ve,OAuthApp:()=>Ie,Octokit:()=>ye,RequestError:()=>Q.RequestError,createNodeMiddleware:()=>fe});var s=i(96049);function r(e,t,i){const s="function"==typeof t?t.endpoint(i):e.request.endpoint(t,i),r="function"==typeof t?t:e.request,n=s.method,o=s.headers;let a=s.url;return{[Symbol.asyncIterator]:()=>({async next(){if(!a)return{done:!0};try{const e=function(e){if(!e.data)return{...e,data:[]};if(!("total_count"in e.data)||"url"in e.data)return e;const t=e.data.incomplete_results,i=e.data.repository_selection,s=e.data.total_count;delete e.data.incomplete_results,delete e.data.repository_selection,delete e.data.total_count;const r=Object.keys(e.data)[0],n=e.data[r];return e.data=n,void 0!==t&&(e.data.incomplete_results=t),void 0!==i&&(e.data.repository_selection=i),e.data.total_count=s,e}(await r({method:n,url:a,headers:o}));return a=((e.headers.link||"").match(/<([^>]+)>;\s*rel="next"/)||[])[1],{value:e}}catch(e){if(409!==e.status)throw e;return a="",{value:{status:200,headers:{},data:[]}}}}})}}function n(e,t,i,s){return"function"==typeof i&&(s=i,i=void 0),o(e,[],r(e,t,i)[Symbol.asyncIterator](),s)}function o(e,t,i,s){return i.next().then((r=>{if(r.done)return t;let n=!1;return t=t.concat(s?s(r.value,(function(){n=!0})):r.value.data),n?t:o(e,t,i,s)}))}var a=Object.assign(n,{iterator:r});function c(e){return{paginate:Object.assign(n.bind(null,e),{iterator:r.bind(null,e)})}}c.VERSION="9.2.1";class l extends Error{constructor(e,t){super(((e,t)=>`The cursor at "${e.join(",")}" did not change its value "${t}" after a page transition. Please make sure your that your query is set up correctly.`)(e.pathInQuery,t)),this.pageInfo=e,this.cursorValue=t,this.name="MissingCursorChangeError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class p extends Error{constructor(e){super(`No pageInfo property found in response. Please make sure to specify the pageInfo in your query. Response-Data: ${JSON.stringify(e,null,2)}`),this.response=e,this.name="MissingPageInfo",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}function A(e){const t=u(e,"pageInfo");if(0===t.length)throw new p(e);return t}const u=(e,t,i=[])=>{for(const r of Object.keys(e)){const n=[...i,r],o=e[r];if(o.hasOwnProperty(t))return n;if(s=o,"[object Object]"===Object.prototype.toString.call(s)){const e=u(o,t,n);if(e.length>0)return e}}var s;return[]},d=(e,t)=>t.reduce(((e,t)=>e[t]),e),h=(e,t,i)=>{const s=t[t.length-1],r=[...t].slice(0,-1),n=d(e,r);n[s]="function"==typeof i?i(n[s]):i},m=e=>e.hasOwnProperty("hasNextPage"),g=e=>(t,i={})=>{let s=!0,r={...i};return{[Symbol.asyncIterator]:()=>({async next(){if(!s)return{done:!0,value:{}};const i=await e.graphql(t,r),n=(e=>{const t=A(e);return{pathInQuery:t,pageInfo:d(e,[...t,"pageInfo"])}})(i),o=(a=n.pageInfo,m(a)?a.endCursor:a.startCursor);var a;if(s=(e=>m(e)?e.hasNextPage:e.hasPreviousPage)(n.pageInfo),s&&o===r.cursor)throw new l(n,o);return r={...r,cursor:o},{done:!1,value:i}}})}},f=(e,t)=>{if(0===Object.keys(e).length)return Object.assign(e,t);const i=A(e),s=[...i,"nodes"],r=d(t,s);r&&h(e,s,(e=>[...e,...r]));const n=[...i,"edges"],o=d(t,n);o&&h(e,n,(e=>[...e,...o]));const a=[...i,"pageInfo"];return h(e,a,d(t,a)),e},E=e=>{const t=g(e);return async(e,i={})=>{let s={};for await(const r of t(e,i))s=f(s,r);return s}};const C=new Map;for(const[e,t]of Object.entries({actions:{addCustomLabelsToSelfHostedRunnerForOrg:["POST /orgs/{org}/actions/runners/{runner_id}/labels"],addCustomLabelsToSelfHostedRunnerForRepo:["POST /repos/{owner}/{repo}/actions/runners/{runner_id}/labels"],addSelectedRepoToOrgSecret:["PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}"],addSelectedRepoToOrgVariable:["PUT /orgs/{org}/actions/variables/{name}/repositories/{repository_id}"],approveWorkflowRun:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/approve"],cancelWorkflowRun:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel"],createEnvironmentVariable:["POST /repositories/{repository_id}/environments/{environment_name}/variables"],createOrUpdateEnvironmentSecret:["PUT /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}"],createOrUpdateOrgSecret:["PUT /orgs/{org}/actions/secrets/{secret_name}"],createOrUpdateRepoSecret:["PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}"],createOrgVariable:["POST /orgs/{org}/actions/variables"],createRegistrationTokenForOrg:["POST /orgs/{org}/actions/runners/registration-token"],createRegistrationTokenForRepo:["POST /repos/{owner}/{repo}/actions/runners/registration-token"],createRemoveTokenForOrg:["POST /orgs/{org}/actions/runners/remove-token"],createRemoveTokenForRepo:["POST /repos/{owner}/{repo}/actions/runners/remove-token"],createRepoVariable:["POST /repos/{owner}/{repo}/actions/variables"],createWorkflowDispatch:["POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches"],deleteActionsCacheById:["DELETE /repos/{owner}/{repo}/actions/caches/{cache_id}"],deleteActionsCacheByKey:["DELETE /repos/{owner}/{repo}/actions/caches{?key,ref}"],deleteArtifact:["DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}"],deleteEnvironmentSecret:["DELETE /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}"],deleteEnvironmentVariable:["DELETE /repositories/{repository_id}/environments/{environment_name}/variables/{name}"],deleteOrgSecret:["DELETE /orgs/{org}/actions/secrets/{secret_name}"],deleteOrgVariable:["DELETE /orgs/{org}/actions/variables/{name}"],deleteRepoSecret:["DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}"],deleteRepoVariable:["DELETE /repos/{owner}/{repo}/actions/variables/{name}"],deleteSelfHostedRunnerFromOrg:["DELETE /orgs/{org}/actions/runners/{runner_id}"],deleteSelfHostedRunnerFromRepo:["DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}"],deleteWorkflowRun:["DELETE /repos/{owner}/{repo}/actions/runs/{run_id}"],deleteWorkflowRunLogs:["DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs"],disableSelectedRepositoryGithubActionsOrganization:["DELETE /orgs/{org}/actions/permissions/repositories/{repository_id}"],disableWorkflow:["PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/disable"],downloadArtifact:["GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}"],downloadJobLogsForWorkflowRun:["GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs"],downloadWorkflowRunAttemptLogs:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/logs"],downloadWorkflowRunLogs:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs"],enableSelectedRepositoryGithubActionsOrganization:["PUT /orgs/{org}/actions/permissions/repositories/{repository_id}"],enableWorkflow:["PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable"],forceCancelWorkflowRun:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/force-cancel"],generateRunnerJitconfigForOrg:["POST /orgs/{org}/actions/runners/generate-jitconfig"],generateRunnerJitconfigForRepo:["POST /repos/{owner}/{repo}/actions/runners/generate-jitconfig"],getActionsCacheList:["GET /repos/{owner}/{repo}/actions/caches"],getActionsCacheUsage:["GET /repos/{owner}/{repo}/actions/cache/usage"],getActionsCacheUsageByRepoForOrg:["GET /orgs/{org}/actions/cache/usage-by-repository"],getActionsCacheUsageForOrg:["GET /orgs/{org}/actions/cache/usage"],getAllowedActionsOrganization:["GET /orgs/{org}/actions/permissions/selected-actions"],getAllowedActionsRepository:["GET /repos/{owner}/{repo}/actions/permissions/selected-actions"],getArtifact:["GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}"],getCustomOidcSubClaimForRepo:["GET /repos/{owner}/{repo}/actions/oidc/customization/sub"],getEnvironmentPublicKey:["GET /repositories/{repository_id}/environments/{environment_name}/secrets/public-key"],getEnvironmentSecret:["GET /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}"],getEnvironmentVariable:["GET /repositories/{repository_id}/environments/{environment_name}/variables/{name}"],getGithubActionsDefaultWorkflowPermissionsOrganization:["GET /orgs/{org}/actions/permissions/workflow"],getGithubActionsDefaultWorkflowPermissionsRepository:["GET /repos/{owner}/{repo}/actions/permissions/workflow"],getGithubActionsPermissionsOrganization:["GET /orgs/{org}/actions/permissions"],getGithubActionsPermissionsRepository:["GET /repos/{owner}/{repo}/actions/permissions"],getJobForWorkflowRun:["GET /repos/{owner}/{repo}/actions/jobs/{job_id}"],getOrgPublicKey:["GET /orgs/{org}/actions/secrets/public-key"],getOrgSecret:["GET /orgs/{org}/actions/secrets/{secret_name}"],getOrgVariable:["GET /orgs/{org}/actions/variables/{name}"],getPendingDeploymentsForRun:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments"],getRepoPermissions:["GET /repos/{owner}/{repo}/actions/permissions",{},{renamed:["actions","getGithubActionsPermissionsRepository"]}],getRepoPublicKey:["GET /repos/{owner}/{repo}/actions/secrets/public-key"],getRepoSecret:["GET /repos/{owner}/{repo}/actions/secrets/{secret_name}"],getRepoVariable:["GET /repos/{owner}/{repo}/actions/variables/{name}"],getReviewsForRun:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/approvals"],getSelfHostedRunnerForOrg:["GET /orgs/{org}/actions/runners/{runner_id}"],getSelfHostedRunnerForRepo:["GET /repos/{owner}/{repo}/actions/runners/{runner_id}"],getWorkflow:["GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}"],getWorkflowAccessToRepository:["GET /repos/{owner}/{repo}/actions/permissions/access"],getWorkflowRun:["GET /repos/{owner}/{repo}/actions/runs/{run_id}"],getWorkflowRunAttempt:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}"],getWorkflowRunUsage:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing"],getWorkflowUsage:["GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/timing"],listArtifactsForRepo:["GET /repos/{owner}/{repo}/actions/artifacts"],listEnvironmentSecrets:["GET /repositories/{repository_id}/environments/{environment_name}/secrets"],listEnvironmentVariables:["GET /repositories/{repository_id}/environments/{environment_name}/variables"],listJobsForWorkflowRun:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs"],listJobsForWorkflowRunAttempt:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs"],listLabelsForSelfHostedRunnerForOrg:["GET /orgs/{org}/actions/runners/{runner_id}/labels"],listLabelsForSelfHostedRunnerForRepo:["GET /repos/{owner}/{repo}/actions/runners/{runner_id}/labels"],listOrgSecrets:["GET /orgs/{org}/actions/secrets"],listOrgVariables:["GET /orgs/{org}/actions/variables"],listRepoOrganizationSecrets:["GET /repos/{owner}/{repo}/actions/organization-secrets"],listRepoOrganizationVariables:["GET /repos/{owner}/{repo}/actions/organization-variables"],listRepoSecrets:["GET /repos/{owner}/{repo}/actions/secrets"],listRepoVariables:["GET /repos/{owner}/{repo}/actions/variables"],listRepoWorkflows:["GET /repos/{owner}/{repo}/actions/workflows"],listRunnerApplicationsForOrg:["GET /orgs/{org}/actions/runners/downloads"],listRunnerApplicationsForRepo:["GET /repos/{owner}/{repo}/actions/runners/downloads"],listSelectedReposForOrgSecret:["GET /orgs/{org}/actions/secrets/{secret_name}/repositories"],listSelectedReposForOrgVariable:["GET /orgs/{org}/actions/variables/{name}/repositories"],listSelectedRepositoriesEnabledGithubActionsOrganization:["GET /orgs/{org}/actions/permissions/repositories"],listSelfHostedRunnersForOrg:["GET /orgs/{org}/actions/runners"],listSelfHostedRunnersForRepo:["GET /repos/{owner}/{repo}/actions/runners"],listWorkflowRunArtifacts:["GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts"],listWorkflowRuns:["GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs"],listWorkflowRunsForRepo:["GET /repos/{owner}/{repo}/actions/runs"],reRunJobForWorkflowRun:["POST /repos/{owner}/{repo}/actions/jobs/{job_id}/rerun"],reRunWorkflow:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun"],reRunWorkflowFailedJobs:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun-failed-jobs"],removeAllCustomLabelsFromSelfHostedRunnerForOrg:["DELETE /orgs/{org}/actions/runners/{runner_id}/labels"],removeAllCustomLabelsFromSelfHostedRunnerForRepo:["DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels"],removeCustomLabelFromSelfHostedRunnerForOrg:["DELETE /orgs/{org}/actions/runners/{runner_id}/labels/{name}"],removeCustomLabelFromSelfHostedRunnerForRepo:["DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels/{name}"],removeSelectedRepoFromOrgSecret:["DELETE /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}"],removeSelectedRepoFromOrgVariable:["DELETE /orgs/{org}/actions/variables/{name}/repositories/{repository_id}"],reviewCustomGatesForRun:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/deployment_protection_rule"],reviewPendingDeploymentsForRun:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments"],setAllowedActionsOrganization:["PUT /orgs/{org}/actions/permissions/selected-actions"],setAllowedActionsRepository:["PUT /repos/{owner}/{repo}/actions/permissions/selected-actions"],setCustomLabelsForSelfHostedRunnerForOrg:["PUT /orgs/{org}/actions/runners/{runner_id}/labels"],setCustomLabelsForSelfHostedRunnerForRepo:["PUT /repos/{owner}/{repo}/actions/runners/{runner_id}/labels"],setCustomOidcSubClaimForRepo:["PUT /repos/{owner}/{repo}/actions/oidc/customization/sub"],setGithubActionsDefaultWorkflowPermissionsOrganization:["PUT /orgs/{org}/actions/permissions/workflow"],setGithubActionsDefaultWorkflowPermissionsRepository:["PUT /repos/{owner}/{repo}/actions/permissions/workflow"],setGithubActionsPermissionsOrganization:["PUT /orgs/{org}/actions/permissions"],setGithubActionsPermissionsRepository:["PUT /repos/{owner}/{repo}/actions/permissions"],setSelectedReposForOrgSecret:["PUT /orgs/{org}/actions/secrets/{secret_name}/repositories"],setSelectedReposForOrgVariable:["PUT /orgs/{org}/actions/variables/{name}/repositories"],setSelectedRepositoriesEnabledGithubActionsOrganization:["PUT /orgs/{org}/actions/permissions/repositories"],setWorkflowAccessToRepository:["PUT /repos/{owner}/{repo}/actions/permissions/access"],updateEnvironmentVariable:["PATCH /repositories/{repository_id}/environments/{environment_name}/variables/{name}"],updateOrgVariable:["PATCH /orgs/{org}/actions/variables/{name}"],updateRepoVariable:["PATCH /repos/{owner}/{repo}/actions/variables/{name}"]},activity:{checkRepoIsStarredByAuthenticatedUser:["GET /user/starred/{owner}/{repo}"],deleteRepoSubscription:["DELETE /repos/{owner}/{repo}/subscription"],deleteThreadSubscription:["DELETE /notifications/threads/{thread_id}/subscription"],getFeeds:["GET /feeds"],getRepoSubscription:["GET /repos/{owner}/{repo}/subscription"],getThread:["GET /notifications/threads/{thread_id}"],getThreadSubscriptionForAuthenticatedUser:["GET /notifications/threads/{thread_id}/subscription"],listEventsForAuthenticatedUser:["GET /users/{username}/events"],listNotificationsForAuthenticatedUser:["GET /notifications"],listOrgEventsForAuthenticatedUser:["GET /users/{username}/events/orgs/{org}"],listPublicEvents:["GET /events"],listPublicEventsForRepoNetwork:["GET /networks/{owner}/{repo}/events"],listPublicEventsForUser:["GET /users/{username}/events/public"],listPublicOrgEvents:["GET /orgs/{org}/events"],listReceivedEventsForUser:["GET /users/{username}/received_events"],listReceivedPublicEventsForUser:["GET /users/{username}/received_events/public"],listRepoEvents:["GET /repos/{owner}/{repo}/events"],listRepoNotificationsForAuthenticatedUser:["GET /repos/{owner}/{repo}/notifications"],listReposStarredByAuthenticatedUser:["GET /user/starred"],listReposStarredByUser:["GET /users/{username}/starred"],listReposWatchedByUser:["GET /users/{username}/subscriptions"],listStargazersForRepo:["GET /repos/{owner}/{repo}/stargazers"],listWatchedReposForAuthenticatedUser:["GET /user/subscriptions"],listWatchersForRepo:["GET /repos/{owner}/{repo}/subscribers"],markNotificationsAsRead:["PUT /notifications"],markRepoNotificationsAsRead:["PUT /repos/{owner}/{repo}/notifications"],markThreadAsDone:["DELETE /notifications/threads/{thread_id}"],markThreadAsRead:["PATCH /notifications/threads/{thread_id}"],setRepoSubscription:["PUT /repos/{owner}/{repo}/subscription"],setThreadSubscription:["PUT /notifications/threads/{thread_id}/subscription"],starRepoForAuthenticatedUser:["PUT /user/starred/{owner}/{repo}"],unstarRepoForAuthenticatedUser:["DELETE /user/starred/{owner}/{repo}"]},apps:{addRepoToInstallation:["PUT /user/installations/{installation_id}/repositories/{repository_id}",{},{renamed:["apps","addRepoToInstallationForAuthenticatedUser"]}],addRepoToInstallationForAuthenticatedUser:["PUT /user/installations/{installation_id}/repositories/{repository_id}"],checkToken:["POST /applications/{client_id}/token"],createFromManifest:["POST /app-manifests/{code}/conversions"],createInstallationAccessToken:["POST /app/installations/{installation_id}/access_tokens"],deleteAuthorization:["DELETE /applications/{client_id}/grant"],deleteInstallation:["DELETE /app/installations/{installation_id}"],deleteToken:["DELETE /applications/{client_id}/token"],getAuthenticated:["GET /app"],getBySlug:["GET /apps/{app_slug}"],getInstallation:["GET /app/installations/{installation_id}"],getOrgInstallation:["GET /orgs/{org}/installation"],getRepoInstallation:["GET /repos/{owner}/{repo}/installation"],getSubscriptionPlanForAccount:["GET /marketplace_listing/accounts/{account_id}"],getSubscriptionPlanForAccountStubbed:["GET /marketplace_listing/stubbed/accounts/{account_id}"],getUserInstallation:["GET /users/{username}/installation"],getWebhookConfigForApp:["GET /app/hook/config"],getWebhookDelivery:["GET /app/hook/deliveries/{delivery_id}"],listAccountsForPlan:["GET /marketplace_listing/plans/{plan_id}/accounts"],listAccountsForPlanStubbed:["GET /marketplace_listing/stubbed/plans/{plan_id}/accounts"],listInstallationReposForAuthenticatedUser:["GET /user/installations/{installation_id}/repositories"],listInstallationRequestsForAuthenticatedApp:["GET /app/installation-requests"],listInstallations:["GET /app/installations"],listInstallationsForAuthenticatedUser:["GET /user/installations"],listPlans:["GET /marketplace_listing/plans"],listPlansStubbed:["GET /marketplace_listing/stubbed/plans"],listReposAccessibleToInstallation:["GET /installation/repositories"],listSubscriptionsForAuthenticatedUser:["GET /user/marketplace_purchases"],listSubscriptionsForAuthenticatedUserStubbed:["GET /user/marketplace_purchases/stubbed"],listWebhookDeliveries:["GET /app/hook/deliveries"],redeliverWebhookDelivery:["POST /app/hook/deliveries/{delivery_id}/attempts"],removeRepoFromInstallation:["DELETE /user/installations/{installation_id}/repositories/{repository_id}",{},{renamed:["apps","removeRepoFromInstallationForAuthenticatedUser"]}],removeRepoFromInstallationForAuthenticatedUser:["DELETE /user/installations/{installation_id}/repositories/{repository_id}"],resetToken:["PATCH /applications/{client_id}/token"],revokeInstallationAccessToken:["DELETE /installation/token"],scopeToken:["POST /applications/{client_id}/token/scoped"],suspendInstallation:["PUT /app/installations/{installation_id}/suspended"],unsuspendInstallation:["DELETE /app/installations/{installation_id}/suspended"],updateWebhookConfigForApp:["PATCH /app/hook/config"]},billing:{getGithubActionsBillingOrg:["GET /orgs/{org}/settings/billing/actions"],getGithubActionsBillingUser:["GET /users/{username}/settings/billing/actions"],getGithubPackagesBillingOrg:["GET /orgs/{org}/settings/billing/packages"],getGithubPackagesBillingUser:["GET /users/{username}/settings/billing/packages"],getSharedStorageBillingOrg:["GET /orgs/{org}/settings/billing/shared-storage"],getSharedStorageBillingUser:["GET /users/{username}/settings/billing/shared-storage"]},checks:{create:["POST /repos/{owner}/{repo}/check-runs"],createSuite:["POST /repos/{owner}/{repo}/check-suites"],get:["GET /repos/{owner}/{repo}/check-runs/{check_run_id}"],getSuite:["GET /repos/{owner}/{repo}/check-suites/{check_suite_id}"],listAnnotations:["GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations"],listForRef:["GET /repos/{owner}/{repo}/commits/{ref}/check-runs"],listForSuite:["GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs"],listSuitesForRef:["GET /repos/{owner}/{repo}/commits/{ref}/check-suites"],rerequestRun:["POST /repos/{owner}/{repo}/check-runs/{check_run_id}/rerequest"],rerequestSuite:["POST /repos/{owner}/{repo}/check-suites/{check_suite_id}/rerequest"],setSuitesPreferences:["PATCH /repos/{owner}/{repo}/check-suites/preferences"],update:["PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}"]},codeScanning:{deleteAnalysis:["DELETE /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}{?confirm_delete}"],getAlert:["GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}",{},{renamedParameters:{alert_id:"alert_number"}}],getAnalysis:["GET /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}"],getCodeqlDatabase:["GET /repos/{owner}/{repo}/code-scanning/codeql/databases/{language}"],getDefaultSetup:["GET /repos/{owner}/{repo}/code-scanning/default-setup"],getSarif:["GET /repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}"],listAlertInstances:["GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances"],listAlertsForOrg:["GET /orgs/{org}/code-scanning/alerts"],listAlertsForRepo:["GET /repos/{owner}/{repo}/code-scanning/alerts"],listAlertsInstances:["GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances",{},{renamed:["codeScanning","listAlertInstances"]}],listCodeqlDatabases:["GET /repos/{owner}/{repo}/code-scanning/codeql/databases"],listRecentAnalyses:["GET /repos/{owner}/{repo}/code-scanning/analyses"],updateAlert:["PATCH /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}"],updateDefaultSetup:["PATCH /repos/{owner}/{repo}/code-scanning/default-setup"],uploadSarif:["POST /repos/{owner}/{repo}/code-scanning/sarifs"]},codesOfConduct:{getAllCodesOfConduct:["GET /codes_of_conduct"],getConductCode:["GET /codes_of_conduct/{key}"]},codespaces:{addRepositoryForSecretForAuthenticatedUser:["PUT /user/codespaces/secrets/{secret_name}/repositories/{repository_id}"],addSelectedRepoToOrgSecret:["PUT /orgs/{org}/codespaces/secrets/{secret_name}/repositories/{repository_id}"],checkPermissionsForDevcontainer:["GET /repos/{owner}/{repo}/codespaces/permissions_check"],codespaceMachinesForAuthenticatedUser:["GET /user/codespaces/{codespace_name}/machines"],createForAuthenticatedUser:["POST /user/codespaces"],createOrUpdateOrgSecret:["PUT /orgs/{org}/codespaces/secrets/{secret_name}"],createOrUpdateRepoSecret:["PUT /repos/{owner}/{repo}/codespaces/secrets/{secret_name}"],createOrUpdateSecretForAuthenticatedUser:["PUT /user/codespaces/secrets/{secret_name}"],createWithPrForAuthenticatedUser:["POST /repos/{owner}/{repo}/pulls/{pull_number}/codespaces"],createWithRepoForAuthenticatedUser:["POST /repos/{owner}/{repo}/codespaces"],deleteForAuthenticatedUser:["DELETE /user/codespaces/{codespace_name}"],deleteFromOrganization:["DELETE /orgs/{org}/members/{username}/codespaces/{codespace_name}"],deleteOrgSecret:["DELETE /orgs/{org}/codespaces/secrets/{secret_name}"],deleteRepoSecret:["DELETE /repos/{owner}/{repo}/codespaces/secrets/{secret_name}"],deleteSecretForAuthenticatedUser:["DELETE /user/codespaces/secrets/{secret_name}"],exportForAuthenticatedUser:["POST /user/codespaces/{codespace_name}/exports"],getCodespacesForUserInOrg:["GET /orgs/{org}/members/{username}/codespaces"],getExportDetailsForAuthenticatedUser:["GET /user/codespaces/{codespace_name}/exports/{export_id}"],getForAuthenticatedUser:["GET /user/codespaces/{codespace_name}"],getOrgPublicKey:["GET /orgs/{org}/codespaces/secrets/public-key"],getOrgSecret:["GET /orgs/{org}/codespaces/secrets/{secret_name}"],getPublicKeyForAuthenticatedUser:["GET /user/codespaces/secrets/public-key"],getRepoPublicKey:["GET /repos/{owner}/{repo}/codespaces/secrets/public-key"],getRepoSecret:["GET /repos/{owner}/{repo}/codespaces/secrets/{secret_name}"],getSecretForAuthenticatedUser:["GET /user/codespaces/secrets/{secret_name}"],listDevcontainersInRepositoryForAuthenticatedUser:["GET /repos/{owner}/{repo}/codespaces/devcontainers"],listForAuthenticatedUser:["GET /user/codespaces"],listInOrganization:["GET /orgs/{org}/codespaces",{},{renamedParameters:{org_id:"org"}}],listInRepositoryForAuthenticatedUser:["GET /repos/{owner}/{repo}/codespaces"],listOrgSecrets:["GET /orgs/{org}/codespaces/secrets"],listRepoSecrets:["GET /repos/{owner}/{repo}/codespaces/secrets"],listRepositoriesForSecretForAuthenticatedUser:["GET /user/codespaces/secrets/{secret_name}/repositories"],listSecretsForAuthenticatedUser:["GET /user/codespaces/secrets"],listSelectedReposForOrgSecret:["GET /orgs/{org}/codespaces/secrets/{secret_name}/repositories"],preFlightWithRepoForAuthenticatedUser:["GET /repos/{owner}/{repo}/codespaces/new"],publishForAuthenticatedUser:["POST /user/codespaces/{codespace_name}/publish"],removeRepositoryForSecretForAuthenticatedUser:["DELETE /user/codespaces/secrets/{secret_name}/repositories/{repository_id}"],removeSelectedRepoFromOrgSecret:["DELETE /orgs/{org}/codespaces/secrets/{secret_name}/repositories/{repository_id}"],repoMachinesForAuthenticatedUser:["GET /repos/{owner}/{repo}/codespaces/machines"],setRepositoriesForSecretForAuthenticatedUser:["PUT /user/codespaces/secrets/{secret_name}/repositories"],setSelectedReposForOrgSecret:["PUT /orgs/{org}/codespaces/secrets/{secret_name}/repositories"],startForAuthenticatedUser:["POST /user/codespaces/{codespace_name}/start"],stopForAuthenticatedUser:["POST /user/codespaces/{codespace_name}/stop"],stopInOrganization:["POST /orgs/{org}/members/{username}/codespaces/{codespace_name}/stop"],updateForAuthenticatedUser:["PATCH /user/codespaces/{codespace_name}"]},copilot:{addCopilotSeatsForTeams:["POST /orgs/{org}/copilot/billing/selected_teams"],addCopilotSeatsForUsers:["POST /orgs/{org}/copilot/billing/selected_users"],cancelCopilotSeatAssignmentForTeams:["DELETE /orgs/{org}/copilot/billing/selected_teams"],cancelCopilotSeatAssignmentForUsers:["DELETE /orgs/{org}/copilot/billing/selected_users"],getCopilotOrganizationDetails:["GET /orgs/{org}/copilot/billing"],getCopilotSeatDetailsForUser:["GET /orgs/{org}/members/{username}/copilot"],listCopilotSeats:["GET /orgs/{org}/copilot/billing/seats"]},dependabot:{addSelectedRepoToOrgSecret:["PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}"],createOrUpdateOrgSecret:["PUT /orgs/{org}/dependabot/secrets/{secret_name}"],createOrUpdateRepoSecret:["PUT /repos/{owner}/{repo}/dependabot/secrets/{secret_name}"],deleteOrgSecret:["DELETE /orgs/{org}/dependabot/secrets/{secret_name}"],deleteRepoSecret:["DELETE /repos/{owner}/{repo}/dependabot/secrets/{secret_name}"],getAlert:["GET /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"],getOrgPublicKey:["GET /orgs/{org}/dependabot/secrets/public-key"],getOrgSecret:["GET /orgs/{org}/dependabot/secrets/{secret_name}"],getRepoPublicKey:["GET /repos/{owner}/{repo}/dependabot/secrets/public-key"],getRepoSecret:["GET /repos/{owner}/{repo}/dependabot/secrets/{secret_name}"],listAlertsForEnterprise:["GET /enterprises/{enterprise}/dependabot/alerts"],listAlertsForOrg:["GET /orgs/{org}/dependabot/alerts"],listAlertsForRepo:["GET /repos/{owner}/{repo}/dependabot/alerts"],listOrgSecrets:["GET /orgs/{org}/dependabot/secrets"],listRepoSecrets:["GET /repos/{owner}/{repo}/dependabot/secrets"],listSelectedReposForOrgSecret:["GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories"],removeSelectedRepoFromOrgSecret:["DELETE /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}"],setSelectedReposForOrgSecret:["PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories"],updateAlert:["PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"]},dependencyGraph:{createRepositorySnapshot:["POST /repos/{owner}/{repo}/dependency-graph/snapshots"],diffRange:["GET /repos/{owner}/{repo}/dependency-graph/compare/{basehead}"],exportSbom:["GET /repos/{owner}/{repo}/dependency-graph/sbom"]},emojis:{get:["GET /emojis"]},gists:{checkIsStarred:["GET /gists/{gist_id}/star"],create:["POST /gists"],createComment:["POST /gists/{gist_id}/comments"],delete:["DELETE /gists/{gist_id}"],deleteComment:["DELETE /gists/{gist_id}/comments/{comment_id}"],fork:["POST /gists/{gist_id}/forks"],get:["GET /gists/{gist_id}"],getComment:["GET /gists/{gist_id}/comments/{comment_id}"],getRevision:["GET /gists/{gist_id}/{sha}"],list:["GET /gists"],listComments:["GET /gists/{gist_id}/comments"],listCommits:["GET /gists/{gist_id}/commits"],listForUser:["GET /users/{username}/gists"],listForks:["GET /gists/{gist_id}/forks"],listPublic:["GET /gists/public"],listStarred:["GET /gists/starred"],star:["PUT /gists/{gist_id}/star"],unstar:["DELETE /gists/{gist_id}/star"],update:["PATCH /gists/{gist_id}"],updateComment:["PATCH /gists/{gist_id}/comments/{comment_id}"]},git:{createBlob:["POST /repos/{owner}/{repo}/git/blobs"],createCommit:["POST /repos/{owner}/{repo}/git/commits"],createRef:["POST /repos/{owner}/{repo}/git/refs"],createTag:["POST /repos/{owner}/{repo}/git/tags"],createTree:["POST /repos/{owner}/{repo}/git/trees"],deleteRef:["DELETE /repos/{owner}/{repo}/git/refs/{ref}"],getBlob:["GET /repos/{owner}/{repo}/git/blobs/{file_sha}"],getCommit:["GET /repos/{owner}/{repo}/git/commits/{commit_sha}"],getRef:["GET /repos/{owner}/{repo}/git/ref/{ref}"],getTag:["GET /repos/{owner}/{repo}/git/tags/{tag_sha}"],getTree:["GET /repos/{owner}/{repo}/git/trees/{tree_sha}"],listMatchingRefs:["GET /repos/{owner}/{repo}/git/matching-refs/{ref}"],updateRef:["PATCH /repos/{owner}/{repo}/git/refs/{ref}"]},gitignore:{getAllTemplates:["GET /gitignore/templates"],getTemplate:["GET /gitignore/templates/{name}"]},interactions:{getRestrictionsForAuthenticatedUser:["GET /user/interaction-limits"],getRestrictionsForOrg:["GET /orgs/{org}/interaction-limits"],getRestrictionsForRepo:["GET /repos/{owner}/{repo}/interaction-limits"],getRestrictionsForYourPublicRepos:["GET /user/interaction-limits",{},{renamed:["interactions","getRestrictionsForAuthenticatedUser"]}],removeRestrictionsForAuthenticatedUser:["DELETE /user/interaction-limits"],removeRestrictionsForOrg:["DELETE /orgs/{org}/interaction-limits"],removeRestrictionsForRepo:["DELETE /repos/{owner}/{repo}/interaction-limits"],removeRestrictionsForYourPublicRepos:["DELETE /user/interaction-limits",{},{renamed:["interactions","removeRestrictionsForAuthenticatedUser"]}],setRestrictionsForAuthenticatedUser:["PUT /user/interaction-limits"],setRestrictionsForOrg:["PUT /orgs/{org}/interaction-limits"],setRestrictionsForRepo:["PUT /repos/{owner}/{repo}/interaction-limits"],setRestrictionsForYourPublicRepos:["PUT /user/interaction-limits",{},{renamed:["interactions","setRestrictionsForAuthenticatedUser"]}]},issues:{addAssignees:["POST /repos/{owner}/{repo}/issues/{issue_number}/assignees"],addLabels:["POST /repos/{owner}/{repo}/issues/{issue_number}/labels"],checkUserCanBeAssigned:["GET /repos/{owner}/{repo}/assignees/{assignee}"],checkUserCanBeAssignedToIssue:["GET /repos/{owner}/{repo}/issues/{issue_number}/assignees/{assignee}"],create:["POST /repos/{owner}/{repo}/issues"],createComment:["POST /repos/{owner}/{repo}/issues/{issue_number}/comments"],createLabel:["POST /repos/{owner}/{repo}/labels"],createMilestone:["POST /repos/{owner}/{repo}/milestones"],deleteComment:["DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}"],deleteLabel:["DELETE /repos/{owner}/{repo}/labels/{name}"],deleteMilestone:["DELETE /repos/{owner}/{repo}/milestones/{milestone_number}"],get:["GET /repos/{owner}/{repo}/issues/{issue_number}"],getComment:["GET /repos/{owner}/{repo}/issues/comments/{comment_id}"],getEvent:["GET /repos/{owner}/{repo}/issues/events/{event_id}"],getLabel:["GET /repos/{owner}/{repo}/labels/{name}"],getMilestone:["GET /repos/{owner}/{repo}/milestones/{milestone_number}"],list:["GET /issues"],listAssignees:["GET /repos/{owner}/{repo}/assignees"],listComments:["GET /repos/{owner}/{repo}/issues/{issue_number}/comments"],listCommentsForRepo:["GET /repos/{owner}/{repo}/issues/comments"],listEvents:["GET /repos/{owner}/{repo}/issues/{issue_number}/events"],listEventsForRepo:["GET /repos/{owner}/{repo}/issues/events"],listEventsForTimeline:["GET /repos/{owner}/{repo}/issues/{issue_number}/timeline"],listForAuthenticatedUser:["GET /user/issues"],listForOrg:["GET /orgs/{org}/issues"],listForRepo:["GET /repos/{owner}/{repo}/issues"],listLabelsForMilestone:["GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels"],listLabelsForRepo:["GET /repos/{owner}/{repo}/labels"],listLabelsOnIssue:["GET /repos/{owner}/{repo}/issues/{issue_number}/labels"],listMilestones:["GET /repos/{owner}/{repo}/milestones"],lock:["PUT /repos/{owner}/{repo}/issues/{issue_number}/lock"],removeAllLabels:["DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels"],removeAssignees:["DELETE /repos/{owner}/{repo}/issues/{issue_number}/assignees"],removeLabel:["DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}"],setLabels:["PUT /repos/{owner}/{repo}/issues/{issue_number}/labels"],unlock:["DELETE /repos/{owner}/{repo}/issues/{issue_number}/lock"],update:["PATCH /repos/{owner}/{repo}/issues/{issue_number}"],updateComment:["PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}"],updateLabel:["PATCH /repos/{owner}/{repo}/labels/{name}"],updateMilestone:["PATCH /repos/{owner}/{repo}/milestones/{milestone_number}"]},licenses:{get:["GET /licenses/{license}"],getAllCommonlyUsed:["GET /licenses"],getForRepo:["GET /repos/{owner}/{repo}/license"]},markdown:{render:["POST /markdown"],renderRaw:["POST /markdown/raw",{headers:{"content-type":"text/plain; charset=utf-8"}}]},meta:{get:["GET /meta"],getAllVersions:["GET /versions"],getOctocat:["GET /octocat"],getZen:["GET /zen"],root:["GET /"]},migrations:{cancelImport:["DELETE /repos/{owner}/{repo}/import",{},{deprecated:"octokit.rest.migrations.cancelImport() is deprecated, see https://docs.github.com/rest/migrations/source-imports#cancel-an-import"}],deleteArchiveForAuthenticatedUser:["DELETE /user/migrations/{migration_id}/archive"],deleteArchiveForOrg:["DELETE /orgs/{org}/migrations/{migration_id}/archive"],downloadArchiveForOrg:["GET /orgs/{org}/migrations/{migration_id}/archive"],getArchiveForAuthenticatedUser:["GET /user/migrations/{migration_id}/archive"],getCommitAuthors:["GET /repos/{owner}/{repo}/import/authors",{},{deprecated:"octokit.rest.migrations.getCommitAuthors() is deprecated, see https://docs.github.com/rest/migrations/source-imports#get-commit-authors"}],getImportStatus:["GET /repos/{owner}/{repo}/import",{},{deprecated:"octokit.rest.migrations.getImportStatus() is deprecated, see https://docs.github.com/rest/migrations/source-imports#get-an-import-status"}],getLargeFiles:["GET /repos/{owner}/{repo}/import/large_files",{},{deprecated:"octokit.rest.migrations.getLargeFiles() is deprecated, see https://docs.github.com/rest/migrations/source-imports#get-large-files"}],getStatusForAuthenticatedUser:["GET /user/migrations/{migration_id}"],getStatusForOrg:["GET /orgs/{org}/migrations/{migration_id}"],listForAuthenticatedUser:["GET /user/migrations"],listForOrg:["GET /orgs/{org}/migrations"],listReposForAuthenticatedUser:["GET /user/migrations/{migration_id}/repositories"],listReposForOrg:["GET /orgs/{org}/migrations/{migration_id}/repositories"],listReposForUser:["GET /user/migrations/{migration_id}/repositories",{},{renamed:["migrations","listReposForAuthenticatedUser"]}],mapCommitAuthor:["PATCH /repos/{owner}/{repo}/import/authors/{author_id}",{},{deprecated:"octokit.rest.migrations.mapCommitAuthor() is deprecated, see https://docs.github.com/rest/migrations/source-imports#map-a-commit-author"}],setLfsPreference:["PATCH /repos/{owner}/{repo}/import/lfs",{},{deprecated:"octokit.rest.migrations.setLfsPreference() is deprecated, see https://docs.github.com/rest/migrations/source-imports#update-git-lfs-preference"}],startForAuthenticatedUser:["POST /user/migrations"],startForOrg:["POST /orgs/{org}/migrations"],startImport:["PUT /repos/{owner}/{repo}/import",{},{deprecated:"octokit.rest.migrations.startImport() is deprecated, see https://docs.github.com/rest/migrations/source-imports#start-an-import"}],unlockRepoForAuthenticatedUser:["DELETE /user/migrations/{migration_id}/repos/{repo_name}/lock"],unlockRepoForOrg:["DELETE /orgs/{org}/migrations/{migration_id}/repos/{repo_name}/lock"],updateImport:["PATCH /repos/{owner}/{repo}/import",{},{deprecated:"octokit.rest.migrations.updateImport() is deprecated, see https://docs.github.com/rest/migrations/source-imports#update-an-import"}]},oidc:{getOidcCustomSubTemplateForOrg:["GET /orgs/{org}/actions/oidc/customization/sub"],updateOidcCustomSubTemplateForOrg:["PUT /orgs/{org}/actions/oidc/customization/sub"]},orgs:{addSecurityManagerTeam:["PUT /orgs/{org}/security-managers/teams/{team_slug}"],assignTeamToOrgRole:["PUT /orgs/{org}/organization-roles/teams/{team_slug}/{role_id}"],assignUserToOrgRole:["PUT /orgs/{org}/organization-roles/users/{username}/{role_id}"],blockUser:["PUT /orgs/{org}/blocks/{username}"],cancelInvitation:["DELETE /orgs/{org}/invitations/{invitation_id}"],checkBlockedUser:["GET /orgs/{org}/blocks/{username}"],checkMembershipForUser:["GET /orgs/{org}/members/{username}"],checkPublicMembershipForUser:["GET /orgs/{org}/public_members/{username}"],convertMemberToOutsideCollaborator:["PUT /orgs/{org}/outside_collaborators/{username}"],createCustomOrganizationRole:["POST /orgs/{org}/organization-roles"],createInvitation:["POST /orgs/{org}/invitations"],createOrUpdateCustomProperties:["PATCH /orgs/{org}/properties/schema"],createOrUpdateCustomPropertiesValuesForRepos:["PATCH /orgs/{org}/properties/values"],createOrUpdateCustomProperty:["PUT /orgs/{org}/properties/schema/{custom_property_name}"],createWebhook:["POST /orgs/{org}/hooks"],delete:["DELETE /orgs/{org}"],deleteCustomOrganizationRole:["DELETE /orgs/{org}/organization-roles/{role_id}"],deleteWebhook:["DELETE /orgs/{org}/hooks/{hook_id}"],enableOrDisableSecurityProductOnAllOrgRepos:["POST /orgs/{org}/{security_product}/{enablement}"],get:["GET /orgs/{org}"],getAllCustomProperties:["GET /orgs/{org}/properties/schema"],getCustomProperty:["GET /orgs/{org}/properties/schema/{custom_property_name}"],getMembershipForAuthenticatedUser:["GET /user/memberships/orgs/{org}"],getMembershipForUser:["GET /orgs/{org}/memberships/{username}"],getOrgRole:["GET /orgs/{org}/organization-roles/{role_id}"],getWebhook:["GET /orgs/{org}/hooks/{hook_id}"],getWebhookConfigForOrg:["GET /orgs/{org}/hooks/{hook_id}/config"],getWebhookDelivery:["GET /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}"],list:["GET /organizations"],listAppInstallations:["GET /orgs/{org}/installations"],listBlockedUsers:["GET /orgs/{org}/blocks"],listCustomPropertiesValuesForRepos:["GET /orgs/{org}/properties/values"],listFailedInvitations:["GET /orgs/{org}/failed_invitations"],listForAuthenticatedUser:["GET /user/orgs"],listForUser:["GET /users/{username}/orgs"],listInvitationTeams:["GET /orgs/{org}/invitations/{invitation_id}/teams"],listMembers:["GET /orgs/{org}/members"],listMembershipsForAuthenticatedUser:["GET /user/memberships/orgs"],listOrgRoleTeams:["GET /orgs/{org}/organization-roles/{role_id}/teams"],listOrgRoleUsers:["GET /orgs/{org}/organization-roles/{role_id}/users"],listOrgRoles:["GET /orgs/{org}/organization-roles"],listOrganizationFineGrainedPermissions:["GET /orgs/{org}/organization-fine-grained-permissions"],listOutsideCollaborators:["GET /orgs/{org}/outside_collaborators"],listPatGrantRepositories:["GET /orgs/{org}/personal-access-tokens/{pat_id}/repositories"],listPatGrantRequestRepositories:["GET /orgs/{org}/personal-access-token-requests/{pat_request_id}/repositories"],listPatGrantRequests:["GET /orgs/{org}/personal-access-token-requests"],listPatGrants:["GET /orgs/{org}/personal-access-tokens"],listPendingInvitations:["GET /orgs/{org}/invitations"],listPublicMembers:["GET /orgs/{org}/public_members"],listSecurityManagerTeams:["GET /orgs/{org}/security-managers"],listWebhookDeliveries:["GET /orgs/{org}/hooks/{hook_id}/deliveries"],listWebhooks:["GET /orgs/{org}/hooks"],patchCustomOrganizationRole:["PATCH /orgs/{org}/organization-roles/{role_id}"],pingWebhook:["POST /orgs/{org}/hooks/{hook_id}/pings"],redeliverWebhookDelivery:["POST /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts"],removeCustomProperty:["DELETE /orgs/{org}/properties/schema/{custom_property_name}"],removeMember:["DELETE /orgs/{org}/members/{username}"],removeMembershipForUser:["DELETE /orgs/{org}/memberships/{username}"],removeOutsideCollaborator:["DELETE /orgs/{org}/outside_collaborators/{username}"],removePublicMembershipForAuthenticatedUser:["DELETE /orgs/{org}/public_members/{username}"],removeSecurityManagerTeam:["DELETE /orgs/{org}/security-managers/teams/{team_slug}"],reviewPatGrantRequest:["POST /orgs/{org}/personal-access-token-requests/{pat_request_id}"],reviewPatGrantRequestsInBulk:["POST /orgs/{org}/personal-access-token-requests"],revokeAllOrgRolesTeam:["DELETE /orgs/{org}/organization-roles/teams/{team_slug}"],revokeAllOrgRolesUser:["DELETE /orgs/{org}/organization-roles/users/{username}"],revokeOrgRoleTeam:["DELETE /orgs/{org}/organization-roles/teams/{team_slug}/{role_id}"],revokeOrgRoleUser:["DELETE /orgs/{org}/organization-roles/users/{username}/{role_id}"],setMembershipForUser:["PUT /orgs/{org}/memberships/{username}"],setPublicMembershipForAuthenticatedUser:["PUT /orgs/{org}/public_members/{username}"],unblockUser:["DELETE /orgs/{org}/blocks/{username}"],update:["PATCH /orgs/{org}"],updateMembershipForAuthenticatedUser:["PATCH /user/memberships/orgs/{org}"],updatePatAccess:["POST /orgs/{org}/personal-access-tokens/{pat_id}"],updatePatAccesses:["POST /orgs/{org}/personal-access-tokens"],updateWebhook:["PATCH /orgs/{org}/hooks/{hook_id}"],updateWebhookConfigForOrg:["PATCH /orgs/{org}/hooks/{hook_id}/config"]},packages:{deletePackageForAuthenticatedUser:["DELETE /user/packages/{package_type}/{package_name}"],deletePackageForOrg:["DELETE /orgs/{org}/packages/{package_type}/{package_name}"],deletePackageForUser:["DELETE /users/{username}/packages/{package_type}/{package_name}"],deletePackageVersionForAuthenticatedUser:["DELETE /user/packages/{package_type}/{package_name}/versions/{package_version_id}"],deletePackageVersionForOrg:["DELETE /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}"],deletePackageVersionForUser:["DELETE /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}"],getAllPackageVersionsForAPackageOwnedByAnOrg:["GET /orgs/{org}/packages/{package_type}/{package_name}/versions",{},{renamed:["packages","getAllPackageVersionsForPackageOwnedByOrg"]}],getAllPackageVersionsForAPackageOwnedByTheAuthenticatedUser:["GET /user/packages/{package_type}/{package_name}/versions",{},{renamed:["packages","getAllPackageVersionsForPackageOwnedByAuthenticatedUser"]}],getAllPackageVersionsForPackageOwnedByAuthenticatedUser:["GET /user/packages/{package_type}/{package_name}/versions"],getAllPackageVersionsForPackageOwnedByOrg:["GET /orgs/{org}/packages/{package_type}/{package_name}/versions"],getAllPackageVersionsForPackageOwnedByUser:["GET /users/{username}/packages/{package_type}/{package_name}/versions"],getPackageForAuthenticatedUser:["GET /user/packages/{package_type}/{package_name}"],getPackageForOrganization:["GET /orgs/{org}/packages/{package_type}/{package_name}"],getPackageForUser:["GET /users/{username}/packages/{package_type}/{package_name}"],getPackageVersionForAuthenticatedUser:["GET /user/packages/{package_type}/{package_name}/versions/{package_version_id}"],getPackageVersionForOrganization:["GET /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}"],getPackageVersionForUser:["GET /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}"],listDockerMigrationConflictingPackagesForAuthenticatedUser:["GET /user/docker/conflicts"],listDockerMigrationConflictingPackagesForOrganization:["GET /orgs/{org}/docker/conflicts"],listDockerMigrationConflictingPackagesForUser:["GET /users/{username}/docker/conflicts"],listPackagesForAuthenticatedUser:["GET /user/packages"],listPackagesForOrganization:["GET /orgs/{org}/packages"],listPackagesForUser:["GET /users/{username}/packages"],restorePackageForAuthenticatedUser:["POST /user/packages/{package_type}/{package_name}/restore{?token}"],restorePackageForOrg:["POST /orgs/{org}/packages/{package_type}/{package_name}/restore{?token}"],restorePackageForUser:["POST /users/{username}/packages/{package_type}/{package_name}/restore{?token}"],restorePackageVersionForAuthenticatedUser:["POST /user/packages/{package_type}/{package_name}/versions/{package_version_id}/restore"],restorePackageVersionForOrg:["POST /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore"],restorePackageVersionForUser:["POST /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore"]},projects:{addCollaborator:["PUT /projects/{project_id}/collaborators/{username}"],createCard:["POST /projects/columns/{column_id}/cards"],createColumn:["POST /projects/{project_id}/columns"],createForAuthenticatedUser:["POST /user/projects"],createForOrg:["POST /orgs/{org}/projects"],createForRepo:["POST /repos/{owner}/{repo}/projects"],delete:["DELETE /projects/{project_id}"],deleteCard:["DELETE /projects/columns/cards/{card_id}"],deleteColumn:["DELETE /projects/columns/{column_id}"],get:["GET /projects/{project_id}"],getCard:["GET /projects/columns/cards/{card_id}"],getColumn:["GET /projects/columns/{column_id}"],getPermissionForUser:["GET /projects/{project_id}/collaborators/{username}/permission"],listCards:["GET /projects/columns/{column_id}/cards"],listCollaborators:["GET /projects/{project_id}/collaborators"],listColumns:["GET /projects/{project_id}/columns"],listForOrg:["GET /orgs/{org}/projects"],listForRepo:["GET /repos/{owner}/{repo}/projects"],listForUser:["GET /users/{username}/projects"],moveCard:["POST /projects/columns/cards/{card_id}/moves"],moveColumn:["POST /projects/columns/{column_id}/moves"],removeCollaborator:["DELETE /projects/{project_id}/collaborators/{username}"],update:["PATCH /projects/{project_id}"],updateCard:["PATCH /projects/columns/cards/{card_id}"],updateColumn:["PATCH /projects/columns/{column_id}"]},pulls:{checkIfMerged:["GET /repos/{owner}/{repo}/pulls/{pull_number}/merge"],create:["POST /repos/{owner}/{repo}/pulls"],createReplyForReviewComment:["POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies"],createReview:["POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews"],createReviewComment:["POST /repos/{owner}/{repo}/pulls/{pull_number}/comments"],deletePendingReview:["DELETE /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}"],deleteReviewComment:["DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}"],dismissReview:["PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/dismissals"],get:["GET /repos/{owner}/{repo}/pulls/{pull_number}"],getReview:["GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}"],getReviewComment:["GET /repos/{owner}/{repo}/pulls/comments/{comment_id}"],list:["GET /repos/{owner}/{repo}/pulls"],listCommentsForReview:["GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments"],listCommits:["GET /repos/{owner}/{repo}/pulls/{pull_number}/commits"],listFiles:["GET /repos/{owner}/{repo}/pulls/{pull_number}/files"],listRequestedReviewers:["GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers"],listReviewComments:["GET /repos/{owner}/{repo}/pulls/{pull_number}/comments"],listReviewCommentsForRepo:["GET /repos/{owner}/{repo}/pulls/comments"],listReviews:["GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews"],merge:["PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge"],removeRequestedReviewers:["DELETE /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers"],requestReviewers:["POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers"],submitReview:["POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/events"],update:["PATCH /repos/{owner}/{repo}/pulls/{pull_number}"],updateBranch:["PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch"],updateReview:["PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}"],updateReviewComment:["PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}"]},rateLimit:{get:["GET /rate_limit"]},reactions:{createForCommitComment:["POST /repos/{owner}/{repo}/comments/{comment_id}/reactions"],createForIssue:["POST /repos/{owner}/{repo}/issues/{issue_number}/reactions"],createForIssueComment:["POST /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions"],createForPullRequestReviewComment:["POST /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions"],createForRelease:["POST /repos/{owner}/{repo}/releases/{release_id}/reactions"],createForTeamDiscussionCommentInOrg:["POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions"],createForTeamDiscussionInOrg:["POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions"],deleteForCommitComment:["DELETE /repos/{owner}/{repo}/comments/{comment_id}/reactions/{reaction_id}"],deleteForIssue:["DELETE /repos/{owner}/{repo}/issues/{issue_number}/reactions/{reaction_id}"],deleteForIssueComment:["DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions/{reaction_id}"],deleteForPullRequestComment:["DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions/{reaction_id}"],deleteForRelease:["DELETE /repos/{owner}/{repo}/releases/{release_id}/reactions/{reaction_id}"],deleteForTeamDiscussion:["DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions/{reaction_id}"],deleteForTeamDiscussionComment:["DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions/{reaction_id}"],listForCommitComment:["GET /repos/{owner}/{repo}/comments/{comment_id}/reactions"],listForIssue:["GET /repos/{owner}/{repo}/issues/{issue_number}/reactions"],listForIssueComment:["GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions"],listForPullRequestReviewComment:["GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions"],listForRelease:["GET /repos/{owner}/{repo}/releases/{release_id}/reactions"],listForTeamDiscussionCommentInOrg:["GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions"],listForTeamDiscussionInOrg:["GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions"]},repos:{acceptInvitation:["PATCH /user/repository_invitations/{invitation_id}",{},{renamed:["repos","acceptInvitationForAuthenticatedUser"]}],acceptInvitationForAuthenticatedUser:["PATCH /user/repository_invitations/{invitation_id}"],addAppAccessRestrictions:["POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps",{},{mapToData:"apps"}],addCollaborator:["PUT /repos/{owner}/{repo}/collaborators/{username}"],addStatusCheckContexts:["POST /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts",{},{mapToData:"contexts"}],addTeamAccessRestrictions:["POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams",{},{mapToData:"teams"}],addUserAccessRestrictions:["POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users",{},{mapToData:"users"}],cancelPagesDeployment:["POST /repos/{owner}/{repo}/pages/deployments/{pages_deployment_id}/cancel"],checkAutomatedSecurityFixes:["GET /repos/{owner}/{repo}/automated-security-fixes"],checkCollaborator:["GET /repos/{owner}/{repo}/collaborators/{username}"],checkVulnerabilityAlerts:["GET /repos/{owner}/{repo}/vulnerability-alerts"],codeownersErrors:["GET /repos/{owner}/{repo}/codeowners/errors"],compareCommits:["GET /repos/{owner}/{repo}/compare/{base}...{head}"],compareCommitsWithBasehead:["GET /repos/{owner}/{repo}/compare/{basehead}"],createAutolink:["POST /repos/{owner}/{repo}/autolinks"],createCommitComment:["POST /repos/{owner}/{repo}/commits/{commit_sha}/comments"],createCommitSignatureProtection:["POST /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures"],createCommitStatus:["POST /repos/{owner}/{repo}/statuses/{sha}"],createDeployKey:["POST /repos/{owner}/{repo}/keys"],createDeployment:["POST /repos/{owner}/{repo}/deployments"],createDeploymentBranchPolicy:["POST /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies"],createDeploymentProtectionRule:["POST /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules"],createDeploymentStatus:["POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses"],createDispatchEvent:["POST /repos/{owner}/{repo}/dispatches"],createForAuthenticatedUser:["POST /user/repos"],createFork:["POST /repos/{owner}/{repo}/forks"],createInOrg:["POST /orgs/{org}/repos"],createOrUpdateCustomPropertiesValues:["PATCH /repos/{owner}/{repo}/properties/values"],createOrUpdateEnvironment:["PUT /repos/{owner}/{repo}/environments/{environment_name}"],createOrUpdateFileContents:["PUT /repos/{owner}/{repo}/contents/{path}"],createOrgRuleset:["POST /orgs/{org}/rulesets"],createPagesDeployment:["POST /repos/{owner}/{repo}/pages/deployments"],createPagesSite:["POST /repos/{owner}/{repo}/pages"],createRelease:["POST /repos/{owner}/{repo}/releases"],createRepoRuleset:["POST /repos/{owner}/{repo}/rulesets"],createTagProtection:["POST /repos/{owner}/{repo}/tags/protection"],createUsingTemplate:["POST /repos/{template_owner}/{template_repo}/generate"],createWebhook:["POST /repos/{owner}/{repo}/hooks"],declineInvitation:["DELETE /user/repository_invitations/{invitation_id}",{},{renamed:["repos","declineInvitationForAuthenticatedUser"]}],declineInvitationForAuthenticatedUser:["DELETE /user/repository_invitations/{invitation_id}"],delete:["DELETE /repos/{owner}/{repo}"],deleteAccessRestrictions:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions"],deleteAdminBranchProtection:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins"],deleteAnEnvironment:["DELETE /repos/{owner}/{repo}/environments/{environment_name}"],deleteAutolink:["DELETE /repos/{owner}/{repo}/autolinks/{autolink_id}"],deleteBranchProtection:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection"],deleteCommitComment:["DELETE /repos/{owner}/{repo}/comments/{comment_id}"],deleteCommitSignatureProtection:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures"],deleteDeployKey:["DELETE /repos/{owner}/{repo}/keys/{key_id}"],deleteDeployment:["DELETE /repos/{owner}/{repo}/deployments/{deployment_id}"],deleteDeploymentBranchPolicy:["DELETE /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}"],deleteFile:["DELETE /repos/{owner}/{repo}/contents/{path}"],deleteInvitation:["DELETE /repos/{owner}/{repo}/invitations/{invitation_id}"],deleteOrgRuleset:["DELETE /orgs/{org}/rulesets/{ruleset_id}"],deletePagesSite:["DELETE /repos/{owner}/{repo}/pages"],deletePullRequestReviewProtection:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews"],deleteRelease:["DELETE /repos/{owner}/{repo}/releases/{release_id}"],deleteReleaseAsset:["DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}"],deleteRepoRuleset:["DELETE /repos/{owner}/{repo}/rulesets/{ruleset_id}"],deleteTagProtection:["DELETE /repos/{owner}/{repo}/tags/protection/{tag_protection_id}"],deleteWebhook:["DELETE /repos/{owner}/{repo}/hooks/{hook_id}"],disableAutomatedSecurityFixes:["DELETE /repos/{owner}/{repo}/automated-security-fixes"],disableDeploymentProtectionRule:["DELETE /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}"],disablePrivateVulnerabilityReporting:["DELETE /repos/{owner}/{repo}/private-vulnerability-reporting"],disableVulnerabilityAlerts:["DELETE /repos/{owner}/{repo}/vulnerability-alerts"],downloadArchive:["GET /repos/{owner}/{repo}/zipball/{ref}",{},{renamed:["repos","downloadZipballArchive"]}],downloadTarballArchive:["GET /repos/{owner}/{repo}/tarball/{ref}"],downloadZipballArchive:["GET /repos/{owner}/{repo}/zipball/{ref}"],enableAutomatedSecurityFixes:["PUT /repos/{owner}/{repo}/automated-security-fixes"],enablePrivateVulnerabilityReporting:["PUT /repos/{owner}/{repo}/private-vulnerability-reporting"],enableVulnerabilityAlerts:["PUT /repos/{owner}/{repo}/vulnerability-alerts"],generateReleaseNotes:["POST /repos/{owner}/{repo}/releases/generate-notes"],get:["GET /repos/{owner}/{repo}"],getAccessRestrictions:["GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions"],getAdminBranchProtection:["GET /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins"],getAllDeploymentProtectionRules:["GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules"],getAllEnvironments:["GET /repos/{owner}/{repo}/environments"],getAllStatusCheckContexts:["GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts"],getAllTopics:["GET /repos/{owner}/{repo}/topics"],getAppsWithAccessToProtectedBranch:["GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps"],getAutolink:["GET /repos/{owner}/{repo}/autolinks/{autolink_id}"],getBranch:["GET /repos/{owner}/{repo}/branches/{branch}"],getBranchProtection:["GET /repos/{owner}/{repo}/branches/{branch}/protection"],getBranchRules:["GET /repos/{owner}/{repo}/rules/branches/{branch}"],getClones:["GET /repos/{owner}/{repo}/traffic/clones"],getCodeFrequencyStats:["GET /repos/{owner}/{repo}/stats/code_frequency"],getCollaboratorPermissionLevel:["GET /repos/{owner}/{repo}/collaborators/{username}/permission"],getCombinedStatusForRef:["GET /repos/{owner}/{repo}/commits/{ref}/status"],getCommit:["GET /repos/{owner}/{repo}/commits/{ref}"],getCommitActivityStats:["GET /repos/{owner}/{repo}/stats/commit_activity"],getCommitComment:["GET /repos/{owner}/{repo}/comments/{comment_id}"],getCommitSignatureProtection:["GET /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures"],getCommunityProfileMetrics:["GET /repos/{owner}/{repo}/community/profile"],getContent:["GET /repos/{owner}/{repo}/contents/{path}"],getContributorsStats:["GET /repos/{owner}/{repo}/stats/contributors"],getCustomDeploymentProtectionRule:["GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}"],getCustomPropertiesValues:["GET /repos/{owner}/{repo}/properties/values"],getDeployKey:["GET /repos/{owner}/{repo}/keys/{key_id}"],getDeployment:["GET /repos/{owner}/{repo}/deployments/{deployment_id}"],getDeploymentBranchPolicy:["GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}"],getDeploymentStatus:["GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id}"],getEnvironment:["GET /repos/{owner}/{repo}/environments/{environment_name}"],getLatestPagesBuild:["GET /repos/{owner}/{repo}/pages/builds/latest"],getLatestRelease:["GET /repos/{owner}/{repo}/releases/latest"],getOrgRuleSuite:["GET /orgs/{org}/rulesets/rule-suites/{rule_suite_id}"],getOrgRuleSuites:["GET /orgs/{org}/rulesets/rule-suites"],getOrgRuleset:["GET /orgs/{org}/rulesets/{ruleset_id}"],getOrgRulesets:["GET /orgs/{org}/rulesets"],getPages:["GET /repos/{owner}/{repo}/pages"],getPagesBuild:["GET /repos/{owner}/{repo}/pages/builds/{build_id}"],getPagesDeployment:["GET /repos/{owner}/{repo}/pages/deployments/{pages_deployment_id}"],getPagesHealthCheck:["GET /repos/{owner}/{repo}/pages/health"],getParticipationStats:["GET /repos/{owner}/{repo}/stats/participation"],getPullRequestReviewProtection:["GET /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews"],getPunchCardStats:["GET /repos/{owner}/{repo}/stats/punch_card"],getReadme:["GET /repos/{owner}/{repo}/readme"],getReadmeInDirectory:["GET /repos/{owner}/{repo}/readme/{dir}"],getRelease:["GET /repos/{owner}/{repo}/releases/{release_id}"],getReleaseAsset:["GET /repos/{owner}/{repo}/releases/assets/{asset_id}"],getReleaseByTag:["GET /repos/{owner}/{repo}/releases/tags/{tag}"],getRepoRuleSuite:["GET /repos/{owner}/{repo}/rulesets/rule-suites/{rule_suite_id}"],getRepoRuleSuites:["GET /repos/{owner}/{repo}/rulesets/rule-suites"],getRepoRuleset:["GET /repos/{owner}/{repo}/rulesets/{ruleset_id}"],getRepoRulesets:["GET /repos/{owner}/{repo}/rulesets"],getStatusChecksProtection:["GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks"],getTeamsWithAccessToProtectedBranch:["GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams"],getTopPaths:["GET /repos/{owner}/{repo}/traffic/popular/paths"],getTopReferrers:["GET /repos/{owner}/{repo}/traffic/popular/referrers"],getUsersWithAccessToProtectedBranch:["GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users"],getViews:["GET /repos/{owner}/{repo}/traffic/views"],getWebhook:["GET /repos/{owner}/{repo}/hooks/{hook_id}"],getWebhookConfigForRepo:["GET /repos/{owner}/{repo}/hooks/{hook_id}/config"],getWebhookDelivery:["GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}"],listActivities:["GET /repos/{owner}/{repo}/activity"],listAutolinks:["GET /repos/{owner}/{repo}/autolinks"],listBranches:["GET /repos/{owner}/{repo}/branches"],listBranchesForHeadCommit:["GET /repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head"],listCollaborators:["GET /repos/{owner}/{repo}/collaborators"],listCommentsForCommit:["GET /repos/{owner}/{repo}/commits/{commit_sha}/comments"],listCommitCommentsForRepo:["GET /repos/{owner}/{repo}/comments"],listCommitStatusesForRef:["GET /repos/{owner}/{repo}/commits/{ref}/statuses"],listCommits:["GET /repos/{owner}/{repo}/commits"],listContributors:["GET /repos/{owner}/{repo}/contributors"],listCustomDeploymentRuleIntegrations:["GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/apps"],listDeployKeys:["GET /repos/{owner}/{repo}/keys"],listDeploymentBranchPolicies:["GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies"],listDeploymentStatuses:["GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses"],listDeployments:["GET /repos/{owner}/{repo}/deployments"],listForAuthenticatedUser:["GET /user/repos"],listForOrg:["GET /orgs/{org}/repos"],listForUser:["GET /users/{username}/repos"],listForks:["GET /repos/{owner}/{repo}/forks"],listInvitations:["GET /repos/{owner}/{repo}/invitations"],listInvitationsForAuthenticatedUser:["GET /user/repository_invitations"],listLanguages:["GET /repos/{owner}/{repo}/languages"],listPagesBuilds:["GET /repos/{owner}/{repo}/pages/builds"],listPublic:["GET /repositories"],listPullRequestsAssociatedWithCommit:["GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls"],listReleaseAssets:["GET /repos/{owner}/{repo}/releases/{release_id}/assets"],listReleases:["GET /repos/{owner}/{repo}/releases"],listTagProtection:["GET /repos/{owner}/{repo}/tags/protection"],listTags:["GET /repos/{owner}/{repo}/tags"],listTeams:["GET /repos/{owner}/{repo}/teams"],listWebhookDeliveries:["GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries"],listWebhooks:["GET /repos/{owner}/{repo}/hooks"],merge:["POST /repos/{owner}/{repo}/merges"],mergeUpstream:["POST /repos/{owner}/{repo}/merge-upstream"],pingWebhook:["POST /repos/{owner}/{repo}/hooks/{hook_id}/pings"],redeliverWebhookDelivery:["POST /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}/attempts"],removeAppAccessRestrictions:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps",{},{mapToData:"apps"}],removeCollaborator:["DELETE /repos/{owner}/{repo}/collaborators/{username}"],removeStatusCheckContexts:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts",{},{mapToData:"contexts"}],removeStatusCheckProtection:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks"],removeTeamAccessRestrictions:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams",{},{mapToData:"teams"}],removeUserAccessRestrictions:["DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users",{},{mapToData:"users"}],renameBranch:["POST /repos/{owner}/{repo}/branches/{branch}/rename"],replaceAllTopics:["PUT /repos/{owner}/{repo}/topics"],requestPagesBuild:["POST /repos/{owner}/{repo}/pages/builds"],setAdminBranchProtection:["POST /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins"],setAppAccessRestrictions:["PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps",{},{mapToData:"apps"}],setStatusCheckContexts:["PUT /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts",{},{mapToData:"contexts"}],setTeamAccessRestrictions:["PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams",{},{mapToData:"teams"}],setUserAccessRestrictions:["PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users",{},{mapToData:"users"}],testPushWebhook:["POST /repos/{owner}/{repo}/hooks/{hook_id}/tests"],transfer:["POST /repos/{owner}/{repo}/transfer"],update:["PATCH /repos/{owner}/{repo}"],updateBranchProtection:["PUT /repos/{owner}/{repo}/branches/{branch}/protection"],updateCommitComment:["PATCH /repos/{owner}/{repo}/comments/{comment_id}"],updateDeploymentBranchPolicy:["PUT /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}"],updateInformationAboutPagesSite:["PUT /repos/{owner}/{repo}/pages"],updateInvitation:["PATCH /repos/{owner}/{repo}/invitations/{invitation_id}"],updateOrgRuleset:["PUT /orgs/{org}/rulesets/{ruleset_id}"],updatePullRequestReviewProtection:["PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews"],updateRelease:["PATCH /repos/{owner}/{repo}/releases/{release_id}"],updateReleaseAsset:["PATCH /repos/{owner}/{repo}/releases/assets/{asset_id}"],updateRepoRuleset:["PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}"],updateStatusCheckPotection:["PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks",{},{renamed:["repos","updateStatusCheckProtection"]}],updateStatusCheckProtection:["PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks"],updateWebhook:["PATCH /repos/{owner}/{repo}/hooks/{hook_id}"],updateWebhookConfigForRepo:["PATCH /repos/{owner}/{repo}/hooks/{hook_id}/config"],uploadReleaseAsset:["POST /repos/{owner}/{repo}/releases/{release_id}/assets{?name,label}",{baseUrl:"https://uploads.github.com"}]},search:{code:["GET /search/code"],commits:["GET /search/commits"],issuesAndPullRequests:["GET /search/issues"],labels:["GET /search/labels"],repos:["GET /search/repositories"],topics:["GET /search/topics"],users:["GET /search/users"]},secretScanning:{getAlert:["GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}"],listAlertsForEnterprise:["GET /enterprises/{enterprise}/secret-scanning/alerts"],listAlertsForOrg:["GET /orgs/{org}/secret-scanning/alerts"],listAlertsForRepo:["GET /repos/{owner}/{repo}/secret-scanning/alerts"],listLocationsForAlert:["GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations"],updateAlert:["PATCH /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}"]},securityAdvisories:{createFork:["POST /repos/{owner}/{repo}/security-advisories/{ghsa_id}/forks"],createPrivateVulnerabilityReport:["POST /repos/{owner}/{repo}/security-advisories/reports"],createRepositoryAdvisory:["POST /repos/{owner}/{repo}/security-advisories"],createRepositoryAdvisoryCveRequest:["POST /repos/{owner}/{repo}/security-advisories/{ghsa_id}/cve"],getGlobalAdvisory:["GET /advisories/{ghsa_id}"],getRepositoryAdvisory:["GET /repos/{owner}/{repo}/security-advisories/{ghsa_id}"],listGlobalAdvisories:["GET /advisories"],listOrgRepositoryAdvisories:["GET /orgs/{org}/security-advisories"],listRepositoryAdvisories:["GET /repos/{owner}/{repo}/security-advisories"],updateRepositoryAdvisory:["PATCH /repos/{owner}/{repo}/security-advisories/{ghsa_id}"]},teams:{addOrUpdateMembershipForUserInOrg:["PUT /orgs/{org}/teams/{team_slug}/memberships/{username}"],addOrUpdateProjectPermissionsInOrg:["PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}"],addOrUpdateRepoPermissionsInOrg:["PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}"],checkPermissionsForProjectInOrg:["GET /orgs/{org}/teams/{team_slug}/projects/{project_id}"],checkPermissionsForRepoInOrg:["GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}"],create:["POST /orgs/{org}/teams"],createDiscussionCommentInOrg:["POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments"],createDiscussionInOrg:["POST /orgs/{org}/teams/{team_slug}/discussions"],deleteDiscussionCommentInOrg:["DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}"],deleteDiscussionInOrg:["DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}"],deleteInOrg:["DELETE /orgs/{org}/teams/{team_slug}"],getByName:["GET /orgs/{org}/teams/{team_slug}"],getDiscussionCommentInOrg:["GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}"],getDiscussionInOrg:["GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}"],getMembershipForUserInOrg:["GET /orgs/{org}/teams/{team_slug}/memberships/{username}"],list:["GET /orgs/{org}/teams"],listChildInOrg:["GET /orgs/{org}/teams/{team_slug}/teams"],listDiscussionCommentsInOrg:["GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments"],listDiscussionsInOrg:["GET /orgs/{org}/teams/{team_slug}/discussions"],listForAuthenticatedUser:["GET /user/teams"],listMembersInOrg:["GET /orgs/{org}/teams/{team_slug}/members"],listPendingInvitationsInOrg:["GET /orgs/{org}/teams/{team_slug}/invitations"],listProjectsInOrg:["GET /orgs/{org}/teams/{team_slug}/projects"],listReposInOrg:["GET /orgs/{org}/teams/{team_slug}/repos"],removeMembershipForUserInOrg:["DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}"],removeProjectInOrg:["DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}"],removeRepoInOrg:["DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}"],updateDiscussionCommentInOrg:["PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}"],updateDiscussionInOrg:["PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}"],updateInOrg:["PATCH /orgs/{org}/teams/{team_slug}"]},users:{addEmailForAuthenticated:["POST /user/emails",{},{renamed:["users","addEmailForAuthenticatedUser"]}],addEmailForAuthenticatedUser:["POST /user/emails"],addSocialAccountForAuthenticatedUser:["POST /user/social_accounts"],block:["PUT /user/blocks/{username}"],checkBlocked:["GET /user/blocks/{username}"],checkFollowingForUser:["GET /users/{username}/following/{target_user}"],checkPersonIsFollowedByAuthenticated:["GET /user/following/{username}"],createGpgKeyForAuthenticated:["POST /user/gpg_keys",{},{renamed:["users","createGpgKeyForAuthenticatedUser"]}],createGpgKeyForAuthenticatedUser:["POST /user/gpg_keys"],createPublicSshKeyForAuthenticated:["POST /user/keys",{},{renamed:["users","createPublicSshKeyForAuthenticatedUser"]}],createPublicSshKeyForAuthenticatedUser:["POST /user/keys"],createSshSigningKeyForAuthenticatedUser:["POST /user/ssh_signing_keys"],deleteEmailForAuthenticated:["DELETE /user/emails",{},{renamed:["users","deleteEmailForAuthenticatedUser"]}],deleteEmailForAuthenticatedUser:["DELETE /user/emails"],deleteGpgKeyForAuthenticated:["DELETE /user/gpg_keys/{gpg_key_id}",{},{renamed:["users","deleteGpgKeyForAuthenticatedUser"]}],deleteGpgKeyForAuthenticatedUser:["DELETE /user/gpg_keys/{gpg_key_id}"],deletePublicSshKeyForAuthenticated:["DELETE /user/keys/{key_id}",{},{renamed:["users","deletePublicSshKeyForAuthenticatedUser"]}],deletePublicSshKeyForAuthenticatedUser:["DELETE /user/keys/{key_id}"],deleteSocialAccountForAuthenticatedUser:["DELETE /user/social_accounts"],deleteSshSigningKeyForAuthenticatedUser:["DELETE /user/ssh_signing_keys/{ssh_signing_key_id}"],follow:["PUT /user/following/{username}"],getAuthenticated:["GET /user"],getByUsername:["GET /users/{username}"],getContextForUser:["GET /users/{username}/hovercard"],getGpgKeyForAuthenticated:["GET /user/gpg_keys/{gpg_key_id}",{},{renamed:["users","getGpgKeyForAuthenticatedUser"]}],getGpgKeyForAuthenticatedUser:["GET /user/gpg_keys/{gpg_key_id}"],getPublicSshKeyForAuthenticated:["GET /user/keys/{key_id}",{},{renamed:["users","getPublicSshKeyForAuthenticatedUser"]}],getPublicSshKeyForAuthenticatedUser:["GET /user/keys/{key_id}"],getSshSigningKeyForAuthenticatedUser:["GET /user/ssh_signing_keys/{ssh_signing_key_id}"],list:["GET /users"],listBlockedByAuthenticated:["GET /user/blocks",{},{renamed:["users","listBlockedByAuthenticatedUser"]}],listBlockedByAuthenticatedUser:["GET /user/blocks"],listEmailsForAuthenticated:["GET /user/emails",{},{renamed:["users","listEmailsForAuthenticatedUser"]}],listEmailsForAuthenticatedUser:["GET /user/emails"],listFollowedByAuthenticated:["GET /user/following",{},{renamed:["users","listFollowedByAuthenticatedUser"]}],listFollowedByAuthenticatedUser:["GET /user/following"],listFollowersForAuthenticatedUser:["GET /user/followers"],listFollowersForUser:["GET /users/{username}/followers"],listFollowingForUser:["GET /users/{username}/following"],listGpgKeysForAuthenticated:["GET /user/gpg_keys",{},{renamed:["users","listGpgKeysForAuthenticatedUser"]}],listGpgKeysForAuthenticatedUser:["GET /user/gpg_keys"],listGpgKeysForUser:["GET /users/{username}/gpg_keys"],listPublicEmailsForAuthenticated:["GET /user/public_emails",{},{renamed:["users","listPublicEmailsForAuthenticatedUser"]}],listPublicEmailsForAuthenticatedUser:["GET /user/public_emails"],listPublicKeysForUser:["GET /users/{username}/keys"],listPublicSshKeysForAuthenticated:["GET /user/keys",{},{renamed:["users","listPublicSshKeysForAuthenticatedUser"]}],listPublicSshKeysForAuthenticatedUser:["GET /user/keys"],listSocialAccountsForAuthenticatedUser:["GET /user/social_accounts"],listSocialAccountsForUser:["GET /users/{username}/social_accounts"],listSshSigningKeysForAuthenticatedUser:["GET /user/ssh_signing_keys"],listSshSigningKeysForUser:["GET /users/{username}/ssh_signing_keys"],setPrimaryEmailVisibilityForAuthenticated:["PATCH /user/email/visibility",{},{renamed:["users","setPrimaryEmailVisibilityForAuthenticatedUser"]}],setPrimaryEmailVisibilityForAuthenticatedUser:["PATCH /user/email/visibility"],unblock:["DELETE /user/blocks/{username}"],unfollow:["DELETE /user/following/{username}"],updateAuthenticated:["PATCH /user"]}}))for(const[i,s]of Object.entries(t)){const[t,r,n]=s,[o,a]=t.split(/ /),c=Object.assign({method:o,url:a},r);C.has(e)||C.set(e,new Map),C.get(e).set(i,{scope:e,methodName:i,endpointDefaults:c,decorations:n})}const y={has:({scope:e},t)=>C.get(e).has(t),getOwnPropertyDescriptor(e,t){return{value:this.get(e,t),configurable:!0,writable:!0,enumerable:!0}},defineProperty:(e,t,i)=>(Object.defineProperty(e.cache,t,i),!0),deleteProperty:(e,t)=>(delete e.cache[t],!0),ownKeys:({scope:e})=>[...C.get(e).keys()],set:(e,t,i)=>e.cache[t]=i,get({octokit:e,scope:t,cache:i},s){if(i[s])return i[s];const r=C.get(t).get(s);if(!r)return;const{endpointDefaults:n,decorations:o}=r;return i[s]=o?function(e,t,i,s,r){const n=e.request.defaults(s);return Object.assign((function(...s){let o=n.endpoint.merge(...s);if(r.mapToData)return o=Object.assign({},o,{data:o[r.mapToData],[r.mapToData]:void 0}),n(o);if(r.renamed){const[s,n]=r.renamed;e.log.warn(`octokit.${t}.${i}() has been renamed to octokit.${s}.${n}()`)}if(r.deprecated&&e.log.warn(r.deprecated),r.renamedParameters){const o=n.endpoint.merge(...s);for(const[s,n]of Object.entries(r.renamedParameters))s in o&&(e.log.warn(`"${s}" parameter is deprecated for "octokit.${t}.${i}()". Use "${n}" instead`),n in o||(o[n]=o[s]),delete o[s]);return n(o)}return n(...s)}),n)}(e,t,s,n,o):e.request.defaults(n),i[s]}};function v(e){const t={};for(const i of C.keys())t[i]=new Proxy({octokit:e,scope:i,cache:{}},y);return t}function I(e){return{rest:v(e)}}async function B(e,t,i,s){if(!i.request||!i.request.request)throw i;if(i.status>=400&&!e.doNotRetry.includes(i.status)){const r=null!=s.request.retries?s.request.retries:e.retries,n=Math.pow((s.request.retryCount||0)+1,2);throw t.retry.retryRequest(i,r,n)}throw i}I.VERSION="10.4.1";var w=i(32722),b=i.n(w),Q=i(98838);async function x(e,t,i,s){const r=new(b());return r.on("failed",(function(t,i){const r=~~t.request.request.retries,n=~~t.request.request.retryAfter;if(s.request.retryCount=i.retryCount+1,r>i.retryCount)return n*e.retryAfterBaseValue})),r.schedule(k.bind(null,e,t,i),s)}async function k(e,t,i,s){const r=await i(i,s);return r.data&&r.data.errors&&/Something went wrong while executing your query/.test(r.data.errors[0].message)?B(e,t,new Q.RequestError(r.data.errors[0].message,500,{request:s,response:r}),s):r}function D(e,t){const i=Object.assign({enabled:!0,retryAfterBaseValue:1e3,doNotRetry:[400,401,403,404,422,451],retries:3},t.retry);return i.enabled&&(e.hook.error("request",B.bind(null,i,e)),e.hook.wrap("request",x.bind(null,i,e))),{retry:{retryRequest:(e,t,i)=>(e.request.request=Object.assign({},e.request.request,{retries:t,retryAfter:i}),e)}}}D.VERSION="0.0.0-development";const S=()=>Promise.resolve();function _(e,t,i){return e.retryLimiter.schedule(R,e,t,i)}async function R(e,t,i){const s="GET"!==i.method&&"HEAD"!==i.method,{pathname:r}=new URL(i.url,"http://github.test"),n="GET"===i.method&&r.startsWith("/search/"),o=r.startsWith("/graphql"),a=~~t.retryCount>0?{priority:0,weight:0}:{};e.clustering&&(a.expiration=6e4),(s||o)&&await e.write.key(e.id).schedule(a,S),s&&e.triggersNotification(r)&&await e.notifications.key(e.id).schedule(a,S),n&&await e.search.key(e.id).schedule(a,S);const c=e.global.key(e.id).schedule(a,t,i);if(o){const e=await c;if(null!=e.data.errors&&e.data.errors.some((e=>"RATE_LIMITED"===e.type)))throw Object.assign(new Error("GraphQL Rate Limit Exceeded"),{response:e,data:e.data})}return c}const T=function(e){const t=`^(?:${["/orgs/{org}/invitations","/orgs/{org}/invitations/{invitation_id}","/orgs/{org}/teams/{team_slug}/discussions","/orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments","/repos/{owner}/{repo}/collaborators/{username}","/repos/{owner}/{repo}/commits/{commit_sha}/comments","/repos/{owner}/{repo}/issues","/repos/{owner}/{repo}/issues/{issue_number}/comments","/repos/{owner}/{repo}/pulls","/repos/{owner}/{repo}/pulls/{pull_number}/comments","/repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies","/repos/{owner}/{repo}/pulls/{pull_number}/merge","/repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers","/repos/{owner}/{repo}/pulls/{pull_number}/reviews","/repos/{owner}/{repo}/releases","/teams/{team_id}/discussions","/teams/{team_id}/discussions/{discussion_number}/comments"].map((e=>e.split("/").map((e=>e.startsWith("{")?"(?:.+?)":e)).join("/"))).map((e=>`(?:${e})`)).join("|")})[^/]*$`;return new RegExp(t,"i")}(),F=T.test.bind(T),N={};function L(e,t){const{enabled:i=!0,Bottleneck:s=b(),id:r="no-id",timeout:n=12e4,connection:o}=t.throttle||{};if(!i)return{};const a={connection:o,timeout:n};null==N.global&&function(e,t){N.global=new e.Group({id:"octokit-global",maxConcurrent:10,...t}),N.search=new e.Group({id:"octokit-search",maxConcurrent:1,minTime:2e3,...t}),N.write=new e.Group({id:"octokit-write",maxConcurrent:1,minTime:1e3,...t}),N.notifications=new e.Group({id:"octokit-notifications",maxConcurrent:1,minTime:3e3,...t})}(s,a);const c=Object.assign({clustering:null!=o,triggersNotification:F,fallbackSecondaryRateRetryAfter:60,retryAfterBaseValue:1e3,retryLimiter:new s,id:r,...N},t.throttle);if("function"!=typeof c.onSecondaryRateLimit||"function"!=typeof c.onRateLimit)throw new Error("octokit/plugin-throttling error:\n You must pass the onSecondaryRateLimit and onRateLimit error handlers.\n See https://octokit.github.io/rest.js/#throttling\n\n const octokit = new Octokit({\n throttle: {\n onSecondaryRateLimit: (retryAfter, options) => {/* ... */},\n onRateLimit: (retryAfter, options) => {/* ... */}\n }\n })\n ");const l={},p=new s.Events(l);return l.on("secondary-limit",c.onSecondaryRateLimit),l.on("rate-limit",c.onRateLimit),l.on("error",(t=>e.log.warn("Error in throttling-plugin limit handler",t))),c.retryLimiter.on("failed",(async function(t,i){const[s,r,n]=i.args,{pathname:o}=new URL(n.url,"http://github.test");if((!o.startsWith("/graphql")||401===t.status)&&403!==t.status)return;const a=~~r.retryCount;r.retryCount=a,n.request.retryCount=a;const{wantRetry:c,retryAfter:l=0}=await async function(){if(/\bsecondary rate\b/i.test(t.message)){const i=Number(t.response.headers["retry-after"])||s.fallbackSecondaryRateRetryAfter;return{wantRetry:await p.trigger("secondary-limit",i,n,e,a),retryAfter:i}}if(null!=t.response.headers&&"0"===t.response.headers["x-ratelimit-remaining"]||(t.response.data?.errors??[]).some((e=>"RATE_LIMITED"===e.type))){const i=new Date(1e3*~~t.response.headers["x-ratelimit-reset"]).getTime(),s=Math.max(Math.ceil((i-Date.now())/1e3)+1,0);return{wantRetry:await p.trigger("rate-limit",s,n,e,a),retryAfter:s}}return{}}();return c?(r.retryCount++,l*s.retryAfterBaseValue):void 0})),e.hook.wrap("request",_.bind(null,c)),{}}L.VERSION="8.2.0",L.triggersNotification=F;var O=i(61786),M=i(32546),U=i(37573);const P=e=>({debug:()=>{},info:()=>{},warn:console.warn.bind(console),error:console.error.bind(console),...e}),G=["branch_protection_configuration","branch_protection_rule.disabled","branch_protection_rule.enabled","branch_protection_rule","branch_protection_rule.created","branch_protection_rule.deleted","branch_protection_rule.edited","check_run","check_run.completed","check_run.created","check_run.requested_action","check_run.rerequested","check_suite","check_suite.completed","check_suite.requested","check_suite.rerequested","code_scanning_alert","code_scanning_alert.appeared_in_branch","code_scanning_alert.closed_by_user","code_scanning_alert.created","code_scanning_alert.fixed","code_scanning_alert.reopened","code_scanning_alert.reopened_by_user","commit_comment","commit_comment.created","create","custom_property","custom_property.created","custom_property.deleted","custom_property_values","custom_property_values.updated","delete","dependabot_alert","dependabot_alert.created","dependabot_alert.dismissed","dependabot_alert.fixed","dependabot_alert.reintroduced","dependabot_alert.reopened","deploy_key","deploy_key.created","deploy_key.deleted","deployment","deployment.created","deployment_protection_rule","deployment_protection_rule.requested","deployment_review","deployment_review.approved","deployment_review.rejected","deployment_review.requested","deployment_status","deployment_status.created","discussion","discussion.answered","discussion.category_changed","discussion.created","discussion.deleted","discussion.edited","discussion.labeled","discussion.locked","discussion.pinned","discussion.transferred","discussion.unanswered","discussion.unlabeled","discussion.unlocked","discussion.unpinned","discussion_comment","discussion_comment.created","discussion_comment.deleted","discussion_comment.edited","fork","github_app_authorization","github_app_authorization.revoked","gollum","installation","installation.created","installation.deleted","installation.new_permissions_accepted","installation.suspend","installation.unsuspend","installation_repositories","installation_repositories.added","installation_repositories.removed","installation_target","installation_target.renamed","issue_comment","issue_comment.created","issue_comment.deleted","issue_comment.edited","issues","issues.assigned","issues.closed","issues.deleted","issues.demilestoned","issues.edited","issues.labeled","issues.locked","issues.milestoned","issues.opened","issues.pinned","issues.reopened","issues.transferred","issues.unassigned","issues.unlabeled","issues.unlocked","issues.unpinned","label","label.created","label.deleted","label.edited","marketplace_purchase","marketplace_purchase.cancelled","marketplace_purchase.changed","marketplace_purchase.pending_change","marketplace_purchase.pending_change_cancelled","marketplace_purchase.purchased","member","member.added","member.edited","member.removed","membership","membership.added","membership.removed","merge_group","merge_group.checks_requested","meta","meta.deleted","milestone","milestone.closed","milestone.created","milestone.deleted","milestone.edited","milestone.opened","org_block","org_block.blocked","org_block.unblocked","organization","organization.deleted","organization.member_added","organization.member_invited","organization.member_removed","organization.renamed","package","package.published","package.updated","page_build","ping","project","project.closed","project.created","project.deleted","project.edited","project.reopened","project_card","project_card.converted","project_card.created","project_card.deleted","project_card.edited","project_card.moved","project_column","project_column.created","project_column.deleted","project_column.edited","project_column.moved","projects_v2_item","projects_v2_item.archived","projects_v2_item.converted","projects_v2_item.created","projects_v2_item.deleted","projects_v2_item.edited","projects_v2_item.reordered","projects_v2_item.restored","public","pull_request","pull_request.assigned","pull_request.auto_merge_disabled","pull_request.auto_merge_enabled","pull_request.closed","pull_request.converted_to_draft","pull_request.demilestoned","pull_request.dequeued","pull_request.edited","pull_request.enqueued","pull_request.labeled","pull_request.locked","pull_request.milestoned","pull_request.opened","pull_request.ready_for_review","pull_request.reopened","pull_request.review_request_removed","pull_request.review_requested","pull_request.synchronize","pull_request.unassigned","pull_request.unlabeled","pull_request.unlocked","pull_request_review","pull_request_review.dismissed","pull_request_review.edited","pull_request_review.submitted","pull_request_review_comment","pull_request_review_comment.created","pull_request_review_comment.deleted","pull_request_review_comment.edited","pull_request_review_thread","pull_request_review_thread.resolved","pull_request_review_thread.unresolved","push","registry_package","registry_package.published","registry_package.updated","release","release.created","release.deleted","release.edited","release.prereleased","release.published","release.released","release.unpublished","repository","repository.archived","repository.created","repository.deleted","repository.edited","repository.privatized","repository.publicized","repository.renamed","repository.transferred","repository.unarchived","repository_dispatch","repository_import","repository_vulnerability_alert","repository_vulnerability_alert.create","repository_vulnerability_alert.dismiss","repository_vulnerability_alert.reopen","repository_vulnerability_alert.resolve","secret_scanning_alert","secret_scanning_alert.created","secret_scanning_alert.reopened","secret_scanning_alert.resolved","secret_scanning_alert.revoked","secret_scanning_alert_location","secret_scanning_alert_location.created","security_advisory","security_advisory.performed","security_advisory.published","security_advisory.updated","security_advisory.withdrawn","sponsorship","sponsorship.cancelled","sponsorship.created","sponsorship.edited","sponsorship.pending_cancellation","sponsorship.pending_tier_change","sponsorship.tier_changed","star","star.created","star.deleted","status","team","team.added_to_repository","team.created","team.deleted","team.edited","team.removed_from_repository","team_add","watch","watch.started","workflow_dispatch","workflow_job","workflow_job.completed","workflow_job.in_progress","workflow_job.queued","workflow_job.waiting","workflow_run","workflow_run.completed","workflow_run.in_progress","workflow_run.requested"];function V(e,t,i){e.hooks[t]||(e.hooks[t]=[]),e.hooks[t].push(i)}function j(e,t,i){if(Array.isArray(t))t.forEach((t=>j(e,t,i)));else{if(["*","error"].includes(t)){const e="*"===t?"any":t,i=`Using the "${t}" event with the regular Webhooks.on() function is not supported. Please use the Webhooks.on${e.charAt(0).toUpperCase()+e.slice(1)}() method instead`;throw new Error(i)}G.includes(t)||e.log.warn(`"${t}" is not a known webhook name (https://developer.github.com/v3/activity/events/types/)`),V(e,t,i)}}function H(e,t){V(e,"*",t)}function J(e,t){V(e,"error",t)}var q=i(14686),Y=i.n(q);function W(e,t){let i;try{i=e(t)}catch(e){console.log('FATAL: Error occurred in "error" event handler'),console.log(e)}i&&i.catch&&i.catch((e=>{console.log('FATAL: Error occurred in "error" event handler'),console.log(e)}))}function z(e,t){const i=e.hooks.error||[];if(t instanceof Error){const e=Object.assign(new(Y())([t]),{event:t,errors:[t]});return i.forEach((t=>W(t,e))),Promise.reject(e)}if(!t||!t.name)throw new(Y())(["Event name not passed"]);if(!t.payload)throw new(Y())(["Event payload not passed"]);const s=function(e,t,i){const s=[e.hooks[i],e.hooks["*"]];return t&&s.unshift(e.hooks[`${i}.${t}`]),[].concat(...s.filter(Boolean))}(e,"action"in t.payload?t.payload.action:null,t.name);if(0===s.length)return Promise.resolve();const r=[],n=s.map((i=>{let s=Promise.resolve(t);return e.transform&&(s=s.then(e.transform)),s.then((e=>i(e))).catch((e=>r.push(Object.assign(e,{event:t}))))}));return Promise.all(n).then((()=>{if(0===r.length)return;const e=new(Y())(r);throw Object.assign(e,{event:t,errors:r}),i.forEach((t=>W(t,e))),e}))}function $(e,t,i){if(Array.isArray(t))t.forEach((t=>$(e,t,i)));else if(e.hooks[t])for(let s=e.hooks[t].length-1;s>=0;s--)if(e.hooks[t][s]===i)return void e.hooks[t].splice(s,1)}function X(e){const t={hooks:{},log:P(e&&e.log)};return e&&e.transform&&(t.transform=e.transform),{on:j.bind(null,t),onAny:H.bind(null,t),onError:J.bind(null,t),removeListener:$.bind(null,t),receive:z.bind(null,t)}}const K=require("node:crypto");var Z=(e=>(e.SHA1="sha1",e.SHA256="sha256",e))(Z||{});const ee="4.1.0";async function te(e,t){const{secret:i,algorithm:s}="object"==typeof e?{secret:e.secret,algorithm:e.algorithm||Z.SHA256}:{secret:e,algorithm:Z.SHA256};if(!i||!t)throw new TypeError("[@octokit/webhooks-methods] secret & payload required for sign()");if("string"!=typeof t)throw new TypeError("[@octokit/webhooks-methods] payload must be a string");if(!Object.values(Z).includes(s))throw new TypeError(`[@octokit/webhooks] Algorithm ${s} is not supported. Must be 'sha1' or 'sha256'`);return`${s}=${(0,K.createHmac)(s,i).update(t).digest("hex")}`}te.VERSION=ee;const ie=require("node:buffer"),se=e=>e.startsWith("sha256=")?"sha256":"sha1";async function re(e,t,i){if(!e||!t||!i)throw new TypeError("[@octokit/webhooks-methods] secret, eventPayload & signature required");if("string"!=typeof t)throw new TypeError("[@octokit/webhooks-methods] eventPayload must be a string");const s=ie.Buffer.from(i),r=se(i),n=ie.Buffer.from(await te({secret:e,algorithm:r},t));return s.length===n.length&&(0,K.timingSafeEqual)(s,n)}async function ne(e,t){if(!await re(e.secret,t.payload,t.signature).catch((()=>!1))){const i=new Error("[@octokit/webhooks] signature does not match event payload and secret");return e.eventHandler.receive(Object.assign(i,{event:t,status:400}))}let i;try{i=JSON.parse(t.payload)}catch(e){throw e.message="Invalid JSON",e.status=400,new(Y())([e])}return e.eventHandler.receive({id:t.id,name:t.name,payload:i})}re.VERSION=ee;class oe{constructor(e){if(!e||!e.secret)throw new Error("[@octokit/webhooks] options.secret required");const t={eventHandler:X(e),secret:e.secret,hooks:{},log:P(e.log)};this.sign=te.bind(null,e.secret),this.verify=re.bind(null,e.secret),this.on=t.eventHandler.on,this.onAny=t.eventHandler.onAny,this.onError=t.eventHandler.onError,this.removeListener=t.eventHandler.removeListener,this.receive=t.eventHandler.receive,this.verifyAndReceive=ne.bind(null,t)}}const ae=["x-github-event","x-hub-signature-256","x-github-delivery"];async function ce(e,t,i,s,r){let n;try{n=new URL(i.url,"http://localhost").pathname}catch(e){return s.writeHead(422,{"content-type":"application/json"}),s.end(JSON.stringify({error:`Request URL could not be parsed: ${i.url}`})),!0}if(n!==t.path)return r?.(),!1;if("POST"!==i.method)return function(e,t){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:`Unknown route: ${e.method} ${e.url}`}))}(i,s),!0;if(!i.headers["content-type"]||!i.headers["content-type"].startsWith("application/json"))return s.writeHead(415,{"content-type":"application/json",accept:"application/json"}),s.end(JSON.stringify({error:'Unsupported "Content-Type" header value. Must be "application/json"'})),!0;const o=function(e){return ae.filter((t=>!(t in e.headers)))}(i).join(", ");if(o)return s.writeHead(400,{"content-type":"application/json"}),s.end(JSON.stringify({error:`Required headers missing: ${o}`})),!0;const a=i.headers["x-github-event"],c=i.headers["x-hub-signature-256"],l=i.headers["x-github-delivery"];t.log.debug(`${a} event received (id: ${l})`);let p=!1;const A=setTimeout((()=>{p=!0,s.statusCode=202,s.end("still processing\n")}),9e3).unref();try{const t=await function(e){return"body"in e?"object"==typeof e.body&&"rawBody"in e&&e.rawBody instanceof Buffer?Promise.resolve(e.rawBody.toString("utf8")):Promise.resolve(e.body):new Promise(((t,i)=>{let s=[];e.on("error",(e=>i(new(Y())([e])))),e.on("data",(e=>s.push(e))),e.on("end",(()=>setImmediate(t,1===s.length?s[0].toString("utf8"):Buffer.concat(s).toString("utf8"))))}))}(i);return await e.verifyAndReceive({id:l,name:a,payload:t,signature:c}),clearTimeout(A),p||s.end("ok\n"),!0}catch(e){if(clearTimeout(A),p)return!0;const i=Array.from(e)[0],r=i.message?`${i.name}: ${i.message}`:"Error: An Unspecified error occurred";return s.statusCode=void 0!==i.status?i.status:500,t.log.error(e),s.end(JSON.stringify({error:r})),!0}}async function le(e,t){return e.octokit.auth({type:"installation",installationId:t,factory(e){const i={...e.octokitOptions,authStrategy:O.createAppAuth,auth:{...e,installationId:t}};return new e.octokit.constructor(i)}})}function pe(e){return Object.assign(Ae.bind(null,e),{iterator:ue.bind(null,e)})}async function Ae(e,t){const i=ue(e)[Symbol.asyncIterator]();let s=await i.next();for(;!s.done;)await t(s.value),s=await i.next()}function ue(e){return{async*[Symbol.asyncIterator](){const t=a.iterator(e.octokit,"GET /app/installations");for await(const{data:i}of t)for(const t of i){const i=await le(e,t.id);yield{octokit:i,installation:t}}}}}function de(e){return Object.assign(he.bind(null,e),{iterator:me.bind(null,e)})}async function he(e,t,i){const s=me(e,i?t:void 0)[Symbol.asyncIterator]();let r=await s.next();for(;!r.done;)i?await i(r.value):await t(r.value),r=await s.next()}function me(e,t){return{async*[Symbol.asyncIterator](){const i=t?function(e,t){return{async*[Symbol.asyncIterator](){yield{octokit:await e.getInstallationOctokit(t)}}}}(e,t.installationId):e.eachInstallation.iterator();for await(const{octokit:e}of i){const t=a.iterator(e,"GET /installation/repositories");for await(const{data:i}of t)for(const t of i)yield{octokit:e,repository:t}}}}}function ge(){}function fe(e,t={}){const i=Object.assign({debug:ge,info:ge,warn:console.warn.bind(console),error:console.error.bind(console)},t.log),s={pathPrefix:"/api/github",...t,log:i},r=function(e,{path:t="/api/github/webhooks",log:i=P()}={}){return ce.bind(null,e,{path:t,log:i})}(e.webhooks,{path:s.pathPrefix+"/webhooks",log:i}),n=(0,M.createNodeMiddleware)(e.oauth,{pathPrefix:s.pathPrefix+"/oauth"});return Ee.bind(null,s.pathPrefix,r,n)}async function Ee(e,t,i,s,r,n){const{pathname:o}=new URL(s.url,"http://localhost");return o.startsWith(`${e}/`)?(o===`${e}/webhooks`?t(s,r):o.startsWith(`${e}/oauth/`)?i(s,r):(0,M.sendNodeResponse)((0,M.unknownRouteResponse)(s),r),!0):(n?.(),!1)}var Ce=class{static{this.VERSION="14.1.0"}static defaults(e){return class extends(this){constructor(...t){super({...e,...t[0]})}}}constructor(e){const t=e.Octokit||s.Octokit,i=Object.assign({appId:e.appId,privateKey:e.privateKey},e.oauth?{clientId:e.oauth.clientId,clientSecret:e.oauth.clientSecret}:{});this.octokit=new t({authStrategy:O.createAppAuth,auth:i,log:e.log}),this.log=Object.assign({debug:()=>{},info:()=>{},warn:console.warn.bind(console),error:console.error.bind(console)},e.log),e.webhooks?this.webhooks=function(e,t){return new oe({secret:t.secret,transform:async t=>{if(!("installation"in t.payload)||"object"!=typeof t.payload.installation){const i=new e.constructor({authStrategy:U.createUnauthenticatedAuth,auth:{reason:'"installation" key missing in webhook event payload'}});return{...t,octokit:i}}const i=t.payload.installation.id,s=await e.auth({type:"installation",installationId:i,factory:e=>new e.octokit.constructor({...e.octokitOptions,authStrategy:O.createAppAuth,auth:{...e,installationId:i}})});return s.hook.before("request",(e=>{e.headers["x-github-delivery"]=t.id})),{...t,octokit:s}}})}(this.octokit,e.webhooks):Object.defineProperty(this,"webhooks",{get(){throw new Error("[@octokit/app] webhooks option not set")}}),e.oauth?this.oauth=new M.OAuthApp({...e.oauth,clientType:"github-app",Octokit:t}):Object.defineProperty(this,"oauth",{get(){throw new Error("[@octokit/app] oauth.clientId / oauth.clientSecret options are not set")}}),this.getInstallationOctokit=le.bind(null,this),this.eachInstallation=pe(this),this.eachRepository=de(this)}},ye=s.Octokit.plugin(I,c,(function(e){return e.graphql,{graphql:Object.assign(e.graphql,{paginate:Object.assign(E(e),{iterator:g(e)})})}}),D,L).defaults({userAgent:"octokit.js/3.1.2",throttle:{onRateLimit:function(e,t,i){if(i.log.warn(`Request quota exhausted for request ${t.method} ${t.url}`),0===t.request.retryCount)return i.log.info(`Retrying after ${e} seconds!`),!0},onSecondaryRateLimit:function(e,t,i){if(i.log.warn(`SecondaryRateLimit detected for request ${t.method} ${t.url}`),0===t.request.retryCount)return i.log.info(`Retrying after ${e} seconds!`),!0}}}),ve=Ce.defaults({Octokit:ye}),Ie=M.OAuthApp.defaults({Octokit:ye})},36219:(e,t,i)=>{var s=i(42065);function r(e){var t=function(){return t.called?t.value:(t.called=!0,t.value=e.apply(this,arguments))};return t.called=!1,t}function n(e){var t=function(){if(t.called)throw new Error(t.onceError);return t.called=!0,t.value=e.apply(this,arguments)},i=e.name||"Function wrapped with `once`";return t.onceError=i+" shouldn't be called more than once",t.called=!1,t}e.exports=s(r),e.exports.strict=s(n),r.proto=r((function(){Object.defineProperty(Function.prototype,"once",{value:function(){return r(this)},configurable:!0}),Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return n(this)},configurable:!0})}))},86015:(e,t,i)=>{"use strict";const s=i(70474),r=new WeakMap,n=(e,t={})=>{if("function"!=typeof e)throw new TypeError("Expected a function");let i,n=0;const o=e.displayName||e.name||"",a=function(...s){if(r.set(a,++n),1===n)i=e.apply(this,s),e=null;else if(!0===t.throw)throw new Error(`Function \`${o}\` can only be called once`);return i};return s(a,e),r.set(a,n),a};e.exports=n,e.exports.default=n,e.exports.callCount=e=>{if(!r.has(e))throw new Error(`The given function \`${e.name}\` is not wrapped by the \`onetime\` package`);return r.get(e)}},7540:(e,t,i)=>{"use strict";const s=i(14521),r=i(47309),n=i(55693),o=i(60881),a=i(6853),c=i(20281),l=i(80762),p=i(27759),A=i(5881),{BufferListStream:u}=i(26221),d=Symbol("text"),h=Symbol("prefixText");class m{constructor(){this.requests=0,this.mutedStream=new u,this.mutedStream.pipe(process.stdout);const e=this;this.ourEmit=function(t,i,...s){const{stdin:r}=process;if(e.requests>0||r.emit===e.ourEmit){if("keypress"===t)return;"data"===t&&i.includes(3)&&process.emit("SIGINT"),Reflect.apply(e.oldEmit,this,[t,i,...s])}else Reflect.apply(process.stdin.emit,this,[t,i,...s])}}start(){this.requests++,1===this.requests&&this.realStart()}stop(){if(this.requests<=0)throw new Error("`stop` called more times than `start`");this.requests--,0===this.requests&&this.realStop()}realStart(){"win32"!==process.platform&&(this.rl=s.createInterface({input:process.stdin,output:this.mutedStream}),this.rl.on("SIGINT",(()=>{0===process.listenerCount("SIGINT")?process.emit("SIGINT"):(this.rl.close(),process.kill(process.pid,"SIGINT"))})))}realStop(){"win32"!==process.platform&&(this.rl.close(),this.rl=void 0)}}let g;class f{constructor(e){g||(g=new m),"string"==typeof e&&(e={text:e}),this.options={text:"",color:"cyan",stream:process.stderr,discardStdin:!0,...e},this.spinner=this.options.spinner,this.color=this.options.color,this.hideCursor=!1!==this.options.hideCursor,this.interval=this.options.interval||this.spinner.interval||100,this.stream=this.options.stream,this.id=void 0,this.isEnabled="boolean"==typeof this.options.isEnabled?this.options.isEnabled:p({stream:this.stream}),this.isSilent="boolean"==typeof this.options.isSilent&&this.options.isSilent,this.text=this.options.text,this.prefixText=this.options.prefixText,this.linesToClear=0,this.indent=this.options.indent,this.discardStdin=this.options.discardStdin,this.isDiscardingStdin=!1}get indent(){return this._indent}set indent(e=0){if(!(e>=0&&Number.isInteger(e)))throw new Error("The `indent` option must be an integer from 0 and up");this._indent=e}_updateInterval(e){void 0!==e&&(this.interval=e)}get spinner(){return this._spinner}set spinner(e){if(this.frameIndex=0,"object"==typeof e){if(void 0===e.frames)throw new Error("The given spinner must have a `frames` property");this._spinner=e}else if(A())if(void 0===e)this._spinner=o.dots;else{if("default"===e||!o[e])throw new Error(`There is no built-in spinner named '${e}'. See https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json for a full list.`);this._spinner=o[e]}else this._spinner=o.line;this._updateInterval(this._spinner.interval)}get text(){return this[d]}set text(e){this[d]=e,this.updateLineCount()}get prefixText(){return this[h]}set prefixText(e){this[h]=e,this.updateLineCount()}get isSpinning(){return void 0!==this.id}getFullPrefixText(e=this[h],t=" "){return"string"==typeof e?e+t:"function"==typeof e?e()+t:""}updateLineCount(){const e=this.stream.columns||80,t=this.getFullPrefixText(this.prefixText,"-");this.lineCount=0;for(const i of c(t+"--"+this[d]).split("\n"))this.lineCount+=Math.max(1,Math.ceil(l(i)/e))}get isEnabled(){return this._isEnabled&&!this.isSilent}set isEnabled(e){if("boolean"!=typeof e)throw new TypeError("The `isEnabled` option must be a boolean");this._isEnabled=e}get isSilent(){return this._isSilent}set isSilent(e){if("boolean"!=typeof e)throw new TypeError("The `isSilent` option must be a boolean");this._isSilent=e}frame(){const{frames:e}=this.spinner;let t=e[this.frameIndex];return this.color&&(t=r[this.color](t)),this.frameIndex=++this.frameIndex%e.length,("string"==typeof this.prefixText&&""!==this.prefixText?this.prefixText+" ":"")+t+("string"==typeof this.text?" "+this.text:"")}clear(){if(!this.isEnabled||!this.stream.isTTY)return this;for(let e=0;e0&&this.stream.moveCursor(0,-1),this.stream.clearLine(),this.stream.cursorTo(this.indent);return this.linesToClear=0,this}render(){return this.isSilent||(this.clear(),this.stream.write(this.frame()),this.linesToClear=this.lineCount),this}start(e){return e&&(this.text=e),this.isSilent?this:this.isEnabled?(this.isSpinning||(this.hideCursor&&n.hide(this.stream),this.discardStdin&&process.stdin.isTTY&&(this.isDiscardingStdin=!0,g.start()),this.render(),this.id=setInterval(this.render.bind(this),this.interval)),this):(this.text&&this.stream.write(`- ${this.text}\n`),this)}stop(){return this.isEnabled?(clearInterval(this.id),this.id=void 0,this.frameIndex=0,this.clear(),this.hideCursor&&n.show(this.stream),this.discardStdin&&process.stdin.isTTY&&this.isDiscardingStdin&&(g.stop(),this.isDiscardingStdin=!1),this):this}succeed(e){return this.stopAndPersist({symbol:a.success,text:e})}fail(e){return this.stopAndPersist({symbol:a.error,text:e})}warn(e){return this.stopAndPersist({symbol:a.warning,text:e})}info(e){return this.stopAndPersist({symbol:a.info,text:e})}stopAndPersist(e={}){if(this.isSilent)return this;const t=e.prefixText||this.prefixText,i=e.text||this.text,s="string"==typeof i?" "+i:"";return this.stop(),this.stream.write(`${this.getFullPrefixText(t," ")}${e.symbol||" "}${s}\n`),this}}e.exports=function(e){return new f(e)},e.exports.promise=(e,t)=>{if("function"!=typeof e.then)throw new TypeError("Parameter `action` must be a Promise");const i=new f(t);return i.start(),(async()=>{try{await e,i.succeed()}catch{i.fail()}})(),i}},23209:e=>{"use strict";e.exports=(e,t)=>(t=t||(()=>{}),e.then((e=>new Promise((e=>{e(t())})).then((()=>e))),(e=>new Promise((e=>{e(t())})).then((()=>{throw e})))))},88464:(e,t,i)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const s=i(21883),r=i(26123),n=i(83991),o=()=>{},a=new r.TimeoutError;t.default=class extends s{constructor(e){var t,i,s,r;if(super(),this._intervalCount=0,this._intervalEnd=0,this._pendingCount=0,this._resolveEmpty=o,this._resolveIdle=o,!("number"==typeof(e=Object.assign({carryoverConcurrencyCount:!1,intervalCap:1/0,interval:0,concurrency:1/0,autoStart:!0,queueClass:n.default},e)).intervalCap&&e.intervalCap>=1))throw new TypeError(`Expected \`intervalCap\` to be a number from 1 and up, got \`${null!==(i=null===(t=e.intervalCap)||void 0===t?void 0:t.toString())&&void 0!==i?i:""}\` (${typeof e.intervalCap})`);if(void 0===e.interval||!(Number.isFinite(e.interval)&&e.interval>=0))throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${null!==(r=null===(s=e.interval)||void 0===s?void 0:s.toString())&&void 0!==r?r:""}\` (${typeof e.interval})`);this._carryoverConcurrencyCount=e.carryoverConcurrencyCount,this._isIntervalIgnored=e.intervalCap===1/0||0===e.interval,this._intervalCap=e.intervalCap,this._interval=e.interval,this._queue=new e.queueClass,this._queueClass=e.queueClass,this.concurrency=e.concurrency,this._timeout=e.timeout,this._throwOnTimeout=!0===e.throwOnTimeout,this._isPaused=!1===e.autoStart}get _doesIntervalAllowAnother(){return this._isIntervalIgnored||this._intervalCount{this._onResumeInterval()}),t)),!0;this._intervalCount=this._carryoverConcurrencyCount?this._pendingCount:0}return!1}_tryToStartAnother(){if(0===this._queue.size)return this._intervalId&&clearInterval(this._intervalId),this._intervalId=void 0,this._resolvePromises(),!1;if(!this._isPaused){const e=!this._isIntervalPaused();if(this._doesIntervalAllowAnother&&this._doesConcurrentAllowAnother){const t=this._queue.dequeue();return!!t&&(this.emit("active"),t(),e&&this._initializeIntervalIfNeeded(),!0)}}return!1}_initializeIntervalIfNeeded(){this._isIntervalIgnored||void 0!==this._intervalId||(this._intervalId=setInterval((()=>{this._onInterval()}),this._interval),this._intervalEnd=Date.now()+this._interval)}_onInterval(){0===this._intervalCount&&0===this._pendingCount&&this._intervalId&&(clearInterval(this._intervalId),this._intervalId=void 0),this._intervalCount=this._carryoverConcurrencyCount?this._pendingCount:0,this._processQueue()}_processQueue(){for(;this._tryToStartAnother(););}get concurrency(){return this._concurrency}set concurrency(e){if(!("number"==typeof e&&e>=1))throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${e}\` (${typeof e})`);this._concurrency=e,this._processQueue()}async add(e,t={}){return new Promise(((i,s)=>{this._queue.enqueue((async()=>{this._pendingCount++,this._intervalCount++;try{const n=void 0===this._timeout&&void 0===t.timeout?e():r.default(Promise.resolve(e()),void 0===t.timeout?this._timeout:t.timeout,(()=>{(void 0===t.throwOnTimeout?this._throwOnTimeout:t.throwOnTimeout)&&s(a)}));i(await n)}catch(e){s(e)}this._next()}),t),this._tryToStartAnother(),this.emit("add")}))}async addAll(e,t){return Promise.all(e.map((async e=>this.add(e,t))))}start(){return this._isPaused?(this._isPaused=!1,this._processQueue(),this):this}pause(){this._isPaused=!0}clear(){this._queue=new this._queueClass}async onEmpty(){if(0!==this._queue.size)return new Promise((e=>{const t=this._resolveEmpty;this._resolveEmpty=()=>{t(),e()}}))}async onIdle(){if(0!==this._pendingCount||0!==this._queue.size)return new Promise((e=>{const t=this._resolveIdle;this._resolveIdle=()=>{t(),e()}}))}get size(){return this._queue.size}sizeBy(e){return this._queue.filter(e).length}get pending(){return this._pendingCount}get isPaused(){return this._isPaused}get timeout(){return this._timeout}set timeout(e){this._timeout=e}}},10392:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,i){let s=0,r=e.length;for(;r>0;){const n=r/2|0;let o=s+n;i(e[o],t)<=0?(s=++o,r-=n+1):r=n}return s}},83991:(e,t,i)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const s=i(10392);t.default=class{constructor(){this._queue=[]}enqueue(e,t){const i={priority:(t=Object.assign({priority:0},t)).priority,run:e};if(this.size&&this._queue[this.size-1].priority>=t.priority)return void this._queue.push(i);const r=s.default(this._queue,i,((e,t)=>t.priority-e.priority));this._queue.splice(r,0,i)}dequeue(){const e=this._queue.shift();return null==e?void 0:e.run}filter(e){return this._queue.filter((t=>t.priority===e.priority)).map((e=>e.run))}get size(){return this._queue.length}}},32656:(e,t,i)=>{"use strict";const s=i(83490),r=["Failed to fetch","NetworkError when attempting to fetch resource.","The Internet connection appears to be offline.","Network request failed"];class n extends Error{constructor(e){super(),e instanceof Error?(this.originalError=e,({message:e}=e)):(this.originalError=new Error(e),this.originalError.stack=this.stack),this.name="AbortError",this.message=e}}const o=(e,t)=>new Promise(((i,o)=>{t={onFailedAttempt:()=>{},retries:10,...t};const a=s.operation(t);a.attempt((async s=>{try{i(await e(s))}catch(e){if(!(e instanceof Error))return void o(new TypeError(`Non-error was thrown: "${e}". You should only throw errors.`));if(e instanceof n)a.stop(),o(e.originalError);else if(e instanceof TypeError&&(c=e.message,!r.includes(c)))a.stop(),o(e);else{((e,t,i)=>{const s=i.retries-(t-1);e.attemptNumber=t,e.retriesLeft=s})(e,s,t);try{await t.onFailedAttempt(e)}catch(e){return void o(e)}a.retry(e)||o(a.mainError())}}var c}))}));e.exports=o,e.exports.default=o,e.exports.AbortError=n},26123:(e,t,i)=>{"use strict";const s=i(23209);class r extends Error{constructor(e){super(e),this.name="TimeoutError"}}const n=(e,t,i)=>new Promise(((n,o)=>{if("number"!=typeof t||t<0)throw new TypeError("Expected `milliseconds` to be a positive number");if(t===1/0)return void n(e);const a=setTimeout((()=>{if("function"==typeof i){try{n(i())}catch(e){o(e)}return}const s=i instanceof Error?i:new r("string"==typeof i?i:`Promise timed out after ${t} milliseconds`);"function"==typeof e.cancel&&e.cancel(),o(s)}),t);s(e.then(n,o),(()=>{clearTimeout(a)}))}));e.exports=n,e.exports.default=n,e.exports.TimeoutError=r},30486:(e,t,i)=>{"use strict";const s=i(30746),r=i(94057),n=e.exports;n.prompt=(e,t)=>(t=r(t),s(e,t)),n.password=(e,t)=>(t=r({silent:!0,trim:!1,default:"",...t}),s(e,t)),n.confirm=(e,t)=>((t=r({trim:!1,...t})).validator.unshift((e=>{switch(e=e.toLowerCase()){case"y":case"yes":case"1":return!0;case"n":case"no":case"0":return!1;default:throw new Error(`Invalid choice: ${e}`)}})),s(e,t)),n.choose=(e,t,i)=>((i=r({trim:!1,...i})).validator.unshift((e=>{const i=t.findIndex((t=>e==t));if(-1===i)throw new Error(`Invalid choice: ${e}`);return t[i]})),s(e,i))},94057:e=>{"use strict";e.exports=function(e){if(void 0!==(e={validator:void 0,retry:!0,trim:!0,default:void 0,useDefaultOnTimeout:!1,silent:!1,replace:"",input:process.stdin,output:process.stdout,timeout:0,...e}).default&&"string"!=typeof e.default)throw new Error("The default option value must be a string");return Array.isArray(e.validator)||(e.validator=e.validator?[e.validator]:[]),e}},30746:(e,t,i)=>{"use strict";const{EOL:s}=i(22037),{promisify:r}=i(73837),n=r(i(91460));e.exports=async function e(t,i){let r;try{r=await n({prompt:t,silent:i.silent,replace:i.replace,input:i.input,output:i.output,timeout:i.timeout})}catch(e){if("timed out"!==e.message||void 0===i.default||!i.useDefaultOnTimeout)throw Object.assign(new Error(e.message),{code:"TIMEDOUT"});r=i.default}if(i.trim&&(r=r.trim()),!r){if(void 0===i.default)return e(t,i);r=i.default}try{for(const e in i.validator)r=await i.validator[e](r)}catch(r){if(i.retry)return r.message&&i.output.write(r.message+s),e(t,i);throw r}return r}},67841:(e,t,i)=>{"use strict";var s=i(57310).parse,r={ftp:21,gopher:70,http:80,https:443,ws:80,wss:443},n=String.prototype.endsWith||function(e){return e.length<=this.length&&-1!==this.indexOf(e,this.length-e.length)};function o(e){return process.env[e.toLowerCase()]||process.env[e.toUpperCase()]||""}t.getProxyForUrl=function(e){var t="string"==typeof e?s(e):e||{},i=t.protocol,a=t.host,c=t.port;if("string"!=typeof a||!a||"string"!=typeof i)return"";if(i=i.split(":",1)[0],!function(e,t){var i=(o("npm_config_no_proxy")||o("no_proxy")).toLowerCase();return!i||"*"!==i&&i.split(/[,\s]/).every((function(i){if(!i)return!0;var s=i.match(/^(.+):(\d+)$/),r=s?s[1]:i,o=s?parseInt(s[2]):0;return!(!o||o===t)||(/^[.*]/.test(r)?("*"===r.charAt(0)&&(r=r.slice(1)),!n.call(e,r)):e!==r)}))}(a=a.replace(/:\d*$/,""),c=parseInt(c)||r[i]||0))return"";var l=o("npm_config_"+i+"_proxy")||o(i+"_proxy")||o("npm_config_proxy")||o("all_proxy");return l&&-1===l.indexOf("://")&&(l=i+"://"+l),l}},91460:(e,t,i)=>{e.exports=function(e,t){if(e.num)throw new Error("read() no longer accepts a char number limit");if(void 0!==e.default&&"string"!=typeof e.default&&"number"!=typeof e.default)throw new Error("default value must be string or number");var i=e.input||process.stdin,n=e.output||process.stdout,o=(e.prompt||"").trim()+" ",a=e.silent,c=!1,l=e.timeout,p=e.default||"";p&&(a?o+="(
); diff --git a/plugins/woocommerce-admin/client/activity-panel/test/index.js b/plugins/woocommerce-admin/client/activity-panel/test/index.js index d364494557f..06db14fb6ab 100644 --- a/plugins/woocommerce-admin/client/activity-panel/test/index.js +++ b/plugins/woocommerce-admin/client/activity-panel/test/index.js @@ -9,7 +9,7 @@ import { createEvent, } from '@testing-library/react'; import { useSelect } from '@wordpress/data'; -import { useUser, useUserPreferences } from '@woocommerce/data'; +import { useUser } from '@woocommerce/data'; import { useState } from '@wordpress/element'; /** @@ -247,82 +247,6 @@ describe( 'Activity Panel', () => { expect( queryByText( 'Finish setup' ) ).toBeDefined(); } ); - describe( 'help panel tooltip', () => { - it( 'should render highlight tooltip when task count is at-least 2, task is not completed, and tooltip not shown yet', () => { - useUserPreferences.mockReturnValue( { - updateUserPreferences: () => {}, - task_list_tracked_started_tasks: { payment: 2 }, - } ); - const { getByText } = render( - - ); - - expect( getByText( '[HighlightTooltip]' ) ).toBeInTheDocument(); - } ); - - it( 'should not render highlight tooltip when task is not visited more then once', () => { - useSelect.mockImplementation( () => ( { - requestingTaskListOptions: false, - setupTaskListComplete: false, - setupTaskListHidden: false, - trackedCompletedTasks: [], - } ) ); - useUserPreferences.mockReturnValue( { - updateUserPreferences: () => {}, - task_list_tracked_started_tasks: { payment: 1 }, - } ); - render( - - ); - - expect( screen.queryByText( '[HighlightTooltip]' ) ).toBeNull(); - - useUserPreferences.mockReturnValue( { - updateUserPreferences: () => {}, - task_list_tracked_started_tasks: {}, - } ); - - render( - - ); - - expect( screen.queryByText( '[HighlightTooltip]' ) ).toBeNull(); - } ); - - it( 'should not render highlight tooltip when task is visited twice, but completed already', () => { - useSelect.mockImplementation( () => ( { - requestingTaskListOptions: false, - setupTaskListComplete: false, - setupTaskListHidden: false, - isCompletedTask: true, - } ) ); - - useUserPreferences.mockReturnValue( { - updateUserPreferences: () => {}, - task_list_tracked_started_tasks: { payment: 2 }, - } ); - - const { queryByText } = render( - - ); - - expect( queryByText( '[HighlightTooltip]' ) ).toBeNull(); - } ); - - it( 'should not render highlight tooltip when task is visited twice, not completed, but already shown', () => { - useUserPreferences.mockReturnValue( { - task_list_tracked_started_tasks: { payment: 2 }, - help_panel_highlight_shown: 'yes', - } ); - - const { queryByText } = render( - - ); - - expect( queryByText( '[HighlightTooltip]' ) ).toBeNull(); - } ); - } ); - describe( 'panel', () => { it( 'should set focus when panel opened/closed without removing element when onTransitionEnd is triggered', () => { const content = 'test'; diff --git a/plugins/woocommerce/changelog/update-remove-tooltip b/plugins/woocommerce/changelog/update-remove-tooltip new file mode 100644 index 00000000000..781580ae128 --- /dev/null +++ b/plugins/woocommerce/changelog/update-remove-tooltip @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Remove "Need help?" modal from onboarding From c06190d5297b76438c475f7309a695c4bb6d51e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Rinc=C3=B3n?= Date: Tue, 20 Aug 2024 09:54:57 +0200 Subject: [PATCH 026/185] CYS - Move the `ai/store-info` endpoint to woocommerce admin API (#50363) * CYS - Move the ai/store-title endpoint to woocommerce admin api * Add middleware and callback * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint error * CYS - Move the ai/business-description endpoint to woocommerce admin API * CYS - Move the ai/store-info endpoint to woocommerce admin API * Update endpoint * Add changefile(s) from automation for the following project(s): woocommerce * Use constant and normalize site title values * Add base AI Endpoint class * Fix lint error * Use the endpoint base class * Revert change * Add changefile(s) from automation for the following project(s): woocommerce * Use ai endpoint class * Add strict types * Fix lint error * Add strict type --------- Co-authored-by: github-actions --- .../design-with-ai/services.ts | 4 +- .../50363-48150-move-store-info-endpoint | 4 + .../src/Admin/API/AI/StoreInfo.php | 81 ++++++++++++++++ plugins/woocommerce/src/Admin/API/Init.php | 1 + .../src/StoreApi/Routes/V1/AI/StoreInfo.php | 94 ------------------- .../src/StoreApi/RoutesController.php | 11 +-- .../src/StoreApi/SchemaController.php | 1 - .../Schemas/V1/AI/StoreInfoSchema.php | 34 ------- 8 files changed, 93 insertions(+), 137 deletions(-) create mode 100644 plugins/woocommerce/changelog/50363-48150-move-store-info-endpoint create mode 100644 plugins/woocommerce/src/Admin/API/AI/StoreInfo.php delete mode 100644 plugins/woocommerce/src/StoreApi/Routes/V1/AI/StoreInfo.php delete mode 100644 plugins/woocommerce/src/StoreApi/Schemas/V1/AI/StoreInfoSchema.php diff --git a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts index 8d43f47ae59..b669a5d0238 100644 --- a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts +++ b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts @@ -206,7 +206,7 @@ const resetPatternsAndProducts = () => async () => { const response = await apiFetch< { is_ai_generated: boolean; } >( { - path: '/wc/private/ai/store-info', + path: '/wc-admin/ai/store-info', method: 'GET', } ); @@ -250,7 +250,7 @@ export const updateStorePatterns = async ( const { is_ai_generated } = await apiFetch< { is_ai_generated: boolean; } >( { - path: '/wc/private/ai/store-info', + path: '/wc-admin/ai/store-info', method: 'GET', } ); diff --git a/plugins/woocommerce/changelog/50363-48150-move-store-info-endpoint b/plugins/woocommerce/changelog/50363-48150-move-store-info-endpoint new file mode 100644 index 00000000000..6325391cf7f --- /dev/null +++ b/plugins/woocommerce/changelog/50363-48150-move-store-info-endpoint @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +CYS - Move the "ai/store-info" endpoint to woocommerce admin API \ No newline at end of file diff --git a/plugins/woocommerce/src/Admin/API/AI/StoreInfo.php b/plugins/woocommerce/src/Admin/API/AI/StoreInfo.php new file mode 100644 index 00000000000..0fb0fb3ab8c --- /dev/null +++ b/plugins/woocommerce/src/Admin/API/AI/StoreInfo.php @@ -0,0 +1,81 @@ +register( + array( + array( + 'methods' => \WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_response' ), + 'permission_callback' => array( Middleware::class, 'is_authorized' ), + ), + 'schema' => array( $this, 'get_schema' ), + ) + ); + } + + /** + * Update the store title powered by AI. + * + * @return WP_Error|WP_REST_Response + */ + public function get_response() { + $product_updater = new UpdateProducts(); + $patterns = PatternsHelper::get_patterns_ai_data_post(); + + $products = $product_updater->fetch_product_ids( 'dummy' ); + + if ( empty( $products ) && ! isset( $patterns ) ) { + return rest_ensure_response( + array( + 'is_ai_generated' => false, + ) + ); + } + + return rest_ensure_response( + array( + 'is_ai_generated' => true, + ) + ); + } + + /** + * Get the Business Description response. + * + * @return array + */ + public function get_schema() { + return array( + 'ai_content_generated' => true, + ); + } +} diff --git a/plugins/woocommerce/src/Admin/API/Init.php b/plugins/woocommerce/src/Admin/API/Init.php index 4750b156c41..afafc423a04 100644 --- a/plugins/woocommerce/src/Admin/API/Init.php +++ b/plugins/woocommerce/src/Admin/API/Init.php @@ -88,6 +88,7 @@ class Init { 'Automattic\WooCommerce\Admin\API\ShippingPartnerSuggestions', 'Automattic\WooCommerce\Admin\API\AI\StoreTitle', 'Automattic\WooCommerce\Admin\API\AI\BusinessDescription', + 'Automattic\WooCommerce\Admin\API\AI\StoreInfo', ); } diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/StoreInfo.php b/plugins/woocommerce/src/StoreApi/Routes/V1/AI/StoreInfo.php deleted file mode 100644 index c3b28d61676..00000000000 --- a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/StoreInfo.php +++ /dev/null @@ -1,94 +0,0 @@ - \WP_REST_Server::READABLE, - 'callback' => [ $this, 'get_response' ], - 'permission_callback' => [ Middleware::class, 'is_authorized' ], - ], - 'schema' => [ $this->schema, 'get_public_item_schema' ], - 'allow_batch' => [ 'v1' => true ], - ]; - } - - /** - * Update the store title powered by AI. - * - * @param \WP_REST_Request $request Request object. - * - * @return bool|string|\WP_Error|\WP_REST_Response - */ - protected function get_route_response( \WP_REST_Request $request ) { - $product_updater = new UpdateProducts(); - $patterns = PatternsHelper::get_patterns_ai_data_post(); - - $products = $product_updater->fetch_product_ids( 'dummy' ); - - if ( empty( $products ) && ! isset( $patterns ) ) { - return rest_ensure_response( - array( - 'is_ai_generated' => false, - ) - ); - } - - return rest_ensure_response( - array( - 'is_ai_generated' => true, - ) - ); - - } - - -} diff --git a/plugins/woocommerce/src/StoreApi/RoutesController.php b/plugins/woocommerce/src/StoreApi/RoutesController.php index 1e4b902a4f5..3b9b5bbe5cf 100644 --- a/plugins/woocommerce/src/StoreApi/RoutesController.php +++ b/plugins/woocommerce/src/StoreApi/RoutesController.php @@ -68,12 +68,11 @@ class RoutesController { ], // @todo Migrate internal AI routes to WooCommerce Core codebase. 'private' => [ - Routes\V1\AI\Images::IDENTIFIER => Routes\V1\AI\Images::class, - Routes\V1\AI\Patterns::IDENTIFIER => Routes\V1\AI\Patterns::class, - Routes\V1\AI\Product::IDENTIFIER => Routes\V1\AI\Product::class, - Routes\V1\AI\Products::IDENTIFIER => Routes\V1\AI\Products::class, - Routes\V1\AI\StoreInfo::IDENTIFIER => Routes\V1\AI\StoreInfo::class, - Routes\V1\Patterns::IDENTIFIER => Routes\V1\Patterns::class, + Routes\V1\AI\Images::IDENTIFIER => Routes\V1\AI\Images::class, + Routes\V1\AI\Patterns::IDENTIFIER => Routes\V1\AI\Patterns::class, + Routes\V1\AI\Product::IDENTIFIER => Routes\V1\AI\Product::class, + Routes\V1\AI\Products::IDENTIFIER => Routes\V1\AI\Products::class, + Routes\V1\Patterns::IDENTIFIER => Routes\V1\Patterns::class, ], ]; } diff --git a/plugins/woocommerce/src/StoreApi/SchemaController.php b/plugins/woocommerce/src/StoreApi/SchemaController.php index 170a151105b..907c60000db 100644 --- a/plugins/woocommerce/src/StoreApi/SchemaController.php +++ b/plugins/woocommerce/src/StoreApi/SchemaController.php @@ -58,7 +58,6 @@ class SchemaController { Schemas\V1\AI\PatternsSchema::IDENTIFIER => Schemas\V1\AI\PatternsSchema::class, Schemas\V1\AI\ProductSchema::IDENTIFIER => Schemas\V1\AI\ProductSchema::class, Schemas\V1\AI\ProductsSchema::IDENTIFIER => Schemas\V1\AI\ProductsSchema::class, - Schemas\V1\AI\StoreInfoSchema::IDENTIFIER => Schemas\V1\AI\StoreInfoSchema::class, Schemas\V1\PatternsSchema::IDENTIFIER => Schemas\V1\PatternsSchema::class, ], ]; diff --git a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/StoreInfoSchema.php b/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/StoreInfoSchema.php deleted file mode 100644 index 251e702d9a9..00000000000 --- a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/StoreInfoSchema.php +++ /dev/null @@ -1,34 +0,0 @@ - Date: Tue, 20 Aug 2024 10:34:27 +0200 Subject: [PATCH 027/185] CYS - Move the `ai/images` endpoint to woocommerce admin API (#50365) * CYS - Move the ai/store-title endpoint to woocommerce admin api * Add middleware and callback * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint error * CYS - Move the ai/business-description endpoint to woocommerce admin API * CYS - Move the ai/store-info endpoint to woocommerce admin API * Update endpoint * Add changefile(s) from automation for the following project(s): woocommerce * CYS - Move the ai/images endpoint to woocommerce admin API * Add changefile(s) from automation for the following project(s): woocommerce * Use constant and normalize site title values * Add base AI Endpoint class * Fix lint error * Use the endpoint base class * Revert change * Add changefile(s) from automation for the following project(s): woocommerce * Use ai endpoint class * Add strict types * Fix lint error * Add strict type * Fix lint and use ai endpoint base * Fix lint --------- Co-authored-by: github-actions --- .../design-with-ai/services.ts | 2 +- .../50365-48150-move-images-endpoint | 4 + .../src/Admin/API/AI/AIEndpoint.php | 4 +- .../woocommerce/src/Admin/API/AI/Images.php | 108 +++++++++++++++ plugins/woocommerce/src/Admin/API/Init.php | 1 + .../src/StoreApi/Routes/V1/AI/Images.php | 130 ------------------ .../src/StoreApi/RoutesController.php | 1 - .../src/StoreApi/SchemaController.php | 1 - .../StoreApi/Schemas/V1/AI/ImagesSchema.php | 45 ------ 9 files changed, 117 insertions(+), 179 deletions(-) create mode 100644 plugins/woocommerce/changelog/50365-48150-move-images-endpoint create mode 100644 plugins/woocommerce/src/Admin/API/AI/Images.php delete mode 100644 plugins/woocommerce/src/StoreApi/Routes/V1/AI/Images.php delete mode 100644 plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ImagesSchema.php diff --git a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts index b669a5d0238..978876e66d9 100644 --- a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts +++ b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts @@ -239,7 +239,7 @@ export const updateStorePatterns = async ( ai_content_generated: boolean; images: { images: Array< unknown >; search_term: string }; } >( { - path: '/wc/private/ai/images', + path: '/wc-admin/ai/images', method: 'POST', data: { business_description: diff --git a/plugins/woocommerce/changelog/50365-48150-move-images-endpoint b/plugins/woocommerce/changelog/50365-48150-move-images-endpoint new file mode 100644 index 00000000000..cceb3d51caf --- /dev/null +++ b/plugins/woocommerce/changelog/50365-48150-move-images-endpoint @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +CYS - Move the `ai/images` endpoint to woocommerce admin API \ No newline at end of file diff --git a/plugins/woocommerce/src/Admin/API/AI/AIEndpoint.php b/plugins/woocommerce/src/Admin/API/AI/AIEndpoint.php index ff177b2fa93..12ea82b0fc5 100644 --- a/plugins/woocommerce/src/Admin/API/AI/AIEndpoint.php +++ b/plugins/woocommerce/src/Admin/API/AI/AIEndpoint.php @@ -51,5 +51,7 @@ abstract class AIEndpoint { * * @return array */ - abstract public function get_schema(); + public function get_schema() { + return array(); + } } diff --git a/plugins/woocommerce/src/Admin/API/AI/Images.php b/plugins/woocommerce/src/Admin/API/AI/Images.php new file mode 100644 index 00000000000..5acd60e2030 --- /dev/null +++ b/plugins/woocommerce/src/Admin/API/AI/Images.php @@ -0,0 +1,108 @@ +register( + array( + array( + 'methods' => \WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'generate_images' ), + 'permission_callback' => array( Middleware::class, 'is_authorized' ), + 'args' => array( + 'business_description' => array( + 'description' => __( 'The business description for a given store.', 'woocommerce' ), + 'type' => 'string', + ), + ), + ), + ) + ); + } + + /** + * Generate Images from Pexels + * + * @param WP_REST_Request $request Request object. + * + * @return WP_Error|WP_REST_Response + */ + public function generate_images( WP_REST_Request $request ) { + + $business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) ); + + if ( empty( $business_description ) ) { + $business_description = get_option( 'woo_ai_describe_store_description' ); + } + + $last_business_description = get_option( 'last_business_description_with_ai_content_generated' ); + + if ( $last_business_description === $business_description ) { + return rest_ensure_response( + $this->prepare_item_for_response( + array( + 'ai_content_generated' => true, + 'images' => array(), + ), + $request + ) + ); + } + + $ai_connection = new Connection(); + + $site_id = $ai_connection->get_site_id(); + + if ( is_wp_error( $site_id ) ) { + return $site_id; + } + + $token = $ai_connection->get_jwt_token( $site_id ); + + if ( is_wp_error( $token ) ) { + return $token; + } + + $images = ( new Pexels() )->get_images( $ai_connection, $token, $business_description ); + + if ( is_wp_error( $images ) ) { + $images = array( + 'images' => array(), + 'search_term' => '', + ); + } + + return rest_ensure_response( + array( + 'ai_content_generated' => true, + 'images' => $images, + ) + ); + } +} diff --git a/plugins/woocommerce/src/Admin/API/Init.php b/plugins/woocommerce/src/Admin/API/Init.php index afafc423a04..9c53054e54a 100644 --- a/plugins/woocommerce/src/Admin/API/Init.php +++ b/plugins/woocommerce/src/Admin/API/Init.php @@ -89,6 +89,7 @@ class Init { 'Automattic\WooCommerce\Admin\API\AI\StoreTitle', 'Automattic\WooCommerce\Admin\API\AI\BusinessDescription', 'Automattic\WooCommerce\Admin\API\AI\StoreInfo', + 'Automattic\WooCommerce\Admin\API\AI\Images', ); } diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Images.php b/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Images.php deleted file mode 100644 index 51cf7d2abc1..00000000000 --- a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Images.php +++ /dev/null @@ -1,130 +0,0 @@ - \WP_REST_Server::CREATABLE, - 'callback' => [ $this, 'get_response' ], - 'permission_callback' => [ Middleware::class, 'is_authorized' ], - 'args' => [ - 'business_description' => [ - 'description' => __( 'The business description for a given store.', 'woocommerce' ), - 'type' => 'string', - ], - ], - ], - 'schema' => [ $this->schema, 'get_public_item_schema' ], - 'allow_batch' => [ 'v1' => true ], - ]; - } - - /** - * Generate Images from Pexels - * - * @param \WP_REST_Request $request Request object. - * - * @return bool|string|\WP_Error|\WP_REST_Response - */ - protected function get_route_post_response( \WP_REST_Request $request ) { - - $business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) ); - - if ( empty( $business_description ) ) { - $business_description = get_option( 'woo_ai_describe_store_description' ); - } - - $last_business_description = get_option( 'last_business_description_with_ai_content_generated' ); - - if ( $last_business_description === $business_description ) { - return rest_ensure_response( - $this->prepare_item_for_response( - [ - 'ai_content_generated' => true, - 'images' => array(), - ], - $request - ) - ); - } - - $ai_connection = new Connection(); - - $site_id = $ai_connection->get_site_id(); - - if ( is_wp_error( $site_id ) ) { - return $this->error_to_response( $site_id ); - } - - $token = $ai_connection->get_jwt_token( $site_id ); - - if ( is_wp_error( $token ) ) { - return $this->error_to_response( $token ); - } - - $images = ( new Pexels() )->get_images( $ai_connection, $token, $business_description ); - - if ( is_wp_error( $images ) ) { - $images = array( - 'images' => array(), - 'search_term' => '', - ); - } - - return rest_ensure_response( - $this->prepare_item_for_response( - [ - 'ai_content_generated' => true, - 'images' => $images, - ], - $request - ) - ); - } -} diff --git a/plugins/woocommerce/src/StoreApi/RoutesController.php b/plugins/woocommerce/src/StoreApi/RoutesController.php index 3b9b5bbe5cf..efe2d07dd4e 100644 --- a/plugins/woocommerce/src/StoreApi/RoutesController.php +++ b/plugins/woocommerce/src/StoreApi/RoutesController.php @@ -68,7 +68,6 @@ class RoutesController { ], // @todo Migrate internal AI routes to WooCommerce Core codebase. 'private' => [ - Routes\V1\AI\Images::IDENTIFIER => Routes\V1\AI\Images::class, Routes\V1\AI\Patterns::IDENTIFIER => Routes\V1\AI\Patterns::class, Routes\V1\AI\Product::IDENTIFIER => Routes\V1\AI\Product::class, Routes\V1\AI\Products::IDENTIFIER => Routes\V1\AI\Products::class, diff --git a/plugins/woocommerce/src/StoreApi/SchemaController.php b/plugins/woocommerce/src/StoreApi/SchemaController.php index 907c60000db..eb8351a4e8d 100644 --- a/plugins/woocommerce/src/StoreApi/SchemaController.php +++ b/plugins/woocommerce/src/StoreApi/SchemaController.php @@ -54,7 +54,6 @@ class SchemaController { Schemas\V1\ProductCategorySchema::IDENTIFIER => Schemas\V1\ProductCategorySchema::class, Schemas\V1\ProductCollectionDataSchema::IDENTIFIER => Schemas\V1\ProductCollectionDataSchema::class, Schemas\V1\ProductReviewSchema::IDENTIFIER => Schemas\V1\ProductReviewSchema::class, - Schemas\V1\AI\ImagesSchema::IDENTIFIER => Schemas\V1\AI\ImagesSchema::class, Schemas\V1\AI\PatternsSchema::IDENTIFIER => Schemas\V1\AI\PatternsSchema::class, Schemas\V1\AI\ProductSchema::IDENTIFIER => Schemas\V1\AI\ProductSchema::class, Schemas\V1\AI\ProductsSchema::IDENTIFIER => Schemas\V1\AI\ProductsSchema::class, diff --git a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ImagesSchema.php b/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ImagesSchema.php deleted file mode 100644 index 317e4c028f6..00000000000 --- a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ImagesSchema.php +++ /dev/null @@ -1,45 +0,0 @@ - Date: Tue, 20 Aug 2024 16:36:20 +0800 Subject: [PATCH 028/185] Add site visibility badge to admin menu (#50775) * Add admin bar badge * Remove previous badge * Update e2e * Add changelog * Fix lint issues * Hide embedded CSS when admin bar is not showing * lint fix * Fix copypasta * Update doc comments * Fix lys e2e tests * Remove unused props * Fix lysTourHidden check * Update site visibility badge ID in tour and admin bar * Add hover effects * Update id in css --------- Co-authored-by: Chi-Hsuan Huang Co-authored-by: Ilyas Foo --- .../woocommerce-admin/client/header/index.js | 14 +-- .../client/launch-your-store/status/index.tsx | 92 +------------------ .../client/launch-your-store/tour/index.tsx | 3 +- .../tour/use-site-visibility-tour.tsx | 2 +- .../changelog/update-coming-soon-badge | 4 + .../includes/class-woocommerce.php | 2 + .../ComingSoon/ComingSoonAdminBarBadge.php | 90 ++++++++++++++++++ .../ComingSoonServiceProvider.php | 3 + .../tests/merchant/launch-your-store.spec.js | 47 +--------- 9 files changed, 111 insertions(+), 146 deletions(-) create mode 100644 plugins/woocommerce/changelog/update-coming-soon-badge create mode 100644 plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php diff --git a/plugins/woocommerce-admin/client/header/index.js b/plugins/woocommerce-admin/client/header/index.js index 6ea6d8ecead..7afa02e8403 100644 --- a/plugins/woocommerce-admin/client/header/index.js +++ b/plugins/woocommerce-admin/client/header/index.js @@ -118,10 +118,9 @@ export const Header = ( { sections, isEmbedded = false, query } ) => { const isHomescreen = isWCAdmin() && getScreenFromPath() === 'homescreen' && ! query.task; - const { isLoading, launchYourStoreEnabled, comingSoon, storePagesOnly } = - useLaunchYourStore( { - enabled: isHomescreen, - } ); + const { isLoading, launchYourStoreEnabled } = useLaunchYourStore( { + enabled: isHomescreen, + } ); const showLaunchYourStoreStatus = isHomescreen && launchYourStoreEnabled && ! isLoading; @@ -157,12 +156,7 @@ export const Header = ( { sections, isEmbedded = false, query } ) => { ) } - { showLaunchYourStoreStatus && ( - - ) } + { showLaunchYourStoreStatus && } diff --git a/plugins/woocommerce-admin/client/launch-your-store/status/index.tsx b/plugins/woocommerce-admin/client/launch-your-store/status/index.tsx index 96f5bb28a2a..b5085fea068 100644 --- a/plugins/woocommerce-admin/client/launch-your-store/status/index.tsx +++ b/plugins/woocommerce-admin/client/launch-your-store/status/index.tsx @@ -1,12 +1,6 @@ /** * External dependencies */ -import { __ } from '@wordpress/i18n'; -import { Icon, moreVertical, edit, cog } from '@wordpress/icons'; -import { Dropdown, Button, MenuGroup, MenuItem } from '@wordpress/components'; -import { getAdminLink, getSetting } from '@woocommerce/settings'; -import clsx from 'clsx'; -import { recordEvent } from '@woocommerce/tracks'; /** * Internal dependencies @@ -14,23 +8,8 @@ import { recordEvent } from '@woocommerce/tracks'; import './style.scss'; import { SiteVisibilityTour } from '../tour'; import { useSiteVisibilityTour } from '../tour/use-site-visibility-tour'; -import { COMING_SOON_PAGE_EDITOR_LINK } from '../constants'; -export const LaunchYourStoreStatus = ( { - comingSoon, - storePagesOnly, -}: { - comingSoon: string; - storePagesOnly: string; -} ) => { - const isComingSoon = comingSoon && comingSoon === 'yes'; - const isStorePagesOnly = - isComingSoon && storePagesOnly && storePagesOnly === 'yes'; - const comingSoonText = isStorePagesOnly - ? __( 'Store coming soon', 'woocommerce' ) - : __( 'Site coming soon', 'woocommerce' ); - const liveText = __( 'Live', 'woocommerce' ); - const dropdownText = isComingSoon ? comingSoonText : liveText; +export const LaunchYourStoreStatus = () => { const { showTour, setShowTour, onClose, shouldTourBeShown } = useSiteVisibilityTour(); @@ -44,75 +23,6 @@ export const LaunchYourStoreStatus = ( { } } /> ) } -
- ( - - ) } - renderContent={ () => ( - <> - - { - recordEvent( - 'launch_your_store_badge_menu_manage_site_visibility_click', - { - site_visibility: isComingSoon - ? 'coming_soon' - : 'live', - } - ); - } } - // @ts-expect-error Prop gets passed down to underlying button https://developer.wordpress.org/block-editor/reference-guides/components/menu-item/#props - href={ getAdminLink( - 'admin.php?page=wc-settings&tab=site-visibility' - ) } - > - - { __( - 'Manage site visibility', - 'woocommerce' - ) } - - { isComingSoon && - getSetting( 'currentThemeIsFSETheme' ) && ( - { - recordEvent( - 'launch_your_store_badge_menu_customize_coming_soon_click' - ); - } } - // @ts-expect-error Prop gets passed down to underlying button https://developer.wordpress.org/block-editor/reference-guides/components/menu-item/#props - href={ - COMING_SOON_PAGE_EDITOR_LINK - } - > - - { __( - 'Customize "Coming soon" page', - 'woocommerce' - ) } - - ) } - - - ) } - /> -
); }; diff --git a/plugins/woocommerce-admin/client/launch-your-store/tour/index.tsx b/plugins/woocommerce-admin/client/launch-your-store/tour/index.tsx index 0ffa96e8189..00f4e52f21d 100644 --- a/plugins/woocommerce-admin/client/launch-your-store/tour/index.tsx +++ b/plugins/woocommerce-admin/client/launch-your-store/tour/index.tsx @@ -49,7 +49,8 @@ export const SiteVisibilityTour = ( { onClose }: { onClose: () => void } ) => { steps: [ { referenceElements: { - desktop: '.woocommerce-lys-status-pill', + desktop: + '#wp-admin-bar-woocommerce-site-visibility-badge', }, meta: { name: 'set-your-store-visibility', diff --git a/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx b/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx index 4dc98b1ee09..52460350aec 100644 --- a/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx +++ b/plugins/woocommerce-admin/client/launch-your-store/tour/use-site-visibility-tour.tsx @@ -51,7 +51,7 @@ export const useSiteVisibilityTour = () => { onClose, shouldTourBeShown: shouldStoreShowLYSTour && - ! ( hasUserDismissedTourMeta || lysTourHidden ), + ! ( hasUserDismissedTourMeta || lysTourHidden === 'yes' ), showTour, setShowTour, }; diff --git a/plugins/woocommerce/changelog/update-coming-soon-badge b/plugins/woocommerce/changelog/update-coming-soon-badge new file mode 100644 index 00000000000..1cd731a6506 --- /dev/null +++ b/plugins/woocommerce/changelog/update-coming-soon-badge @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Move site visibility badge to admin bar. diff --git a/plugins/woocommerce/includes/class-woocommerce.php b/plugins/woocommerce/includes/class-woocommerce.php index a8949206d52..5daa716f66d 100644 --- a/plugins/woocommerce/includes/class-woocommerce.php +++ b/plugins/woocommerce/includes/class-woocommerce.php @@ -10,6 +10,7 @@ defined( 'ABSPATH' ) || exit; use Automattic\WooCommerce\Internal\AssignDefaultCategory; use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController; +use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonAdminBarBadge; use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonCacheInvalidator; use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonRequestHandler; use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController; @@ -329,6 +330,7 @@ final class WooCommerce { $container->get( WebhookUtil::class ); $container->get( Marketplace::class ); $container->get( TimeUtil::class ); + $container->get( ComingSoonAdminBarBadge::class ); $container->get( ComingSoonCacheInvalidator::class ); $container->get( ComingSoonRequestHandler::class ); diff --git a/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php b/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php new file mode 100644 index 00000000000..4ce688775a3 --- /dev/null +++ b/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php @@ -0,0 +1,90 @@ + __( 'Coming soon', 'woocommerce' ), + 'store-coming-soon' => __( 'Store coming soon', 'woocommerce' ), + 'live' => __( 'Live', 'woocommerce' ), + ); + + if ( get_option( 'woocommerce_coming_soon' ) === 'yes' ) { + if ( get_option( 'woocommerce_store_pages_only' ) === 'yes' ) { + $key = 'store-coming-soon'; + } else { + $key = 'coming-soon'; + } + } else { + $key = 'live'; + } + + $args = array( + 'id' => 'woocommerce-site-visibility-badge', + 'title' => $labels[ $key ], + 'href' => admin_url( 'admin.php?page=wc-settings&tab=site-visibility' ), + 'meta' => array( + 'class' => 'woocommerce-site-status-badge-' . $key, + ), + ); + $wp_admin_bar->add_node( $args ); + } + + /** + * Output CSS for site visibility badge. + * + * @internal + */ + public function output_css() { + if ( is_admin_bar_showing() ) { + echo ''; + } + } +} diff --git a/plugins/woocommerce/src/Internal/DependencyManagement/ServiceProviders/ComingSoonServiceProvider.php b/plugins/woocommerce/src/Internal/DependencyManagement/ServiceProviders/ComingSoonServiceProvider.php index ba544bfaba0..10dc40ac8aa 100644 --- a/plugins/woocommerce/src/Internal/DependencyManagement/ServiceProviders/ComingSoonServiceProvider.php +++ b/plugins/woocommerce/src/Internal/DependencyManagement/ServiceProviders/ComingSoonServiceProvider.php @@ -3,6 +3,7 @@ namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders; use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider; +use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonAdminBarBadge; use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonCacheInvalidator; use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonRequestHandler; use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonHelper; @@ -18,6 +19,7 @@ class ComingSoonServiceProvider extends AbstractServiceProvider { * @var array */ protected $provides = array( + ComingSoonAdminBarBadge::class, ComingSoonCacheInvalidator::class, ComingSoonHelper::class, ComingSoonRequestHandler::class, @@ -27,6 +29,7 @@ class ComingSoonServiceProvider extends AbstractServiceProvider { * Register the classes. */ public function register() { + $this->add( ComingSoonAdminBarBadge::class ); $this->add( ComingSoonCacheInvalidator::class ); $this->add( ComingSoonHelper::class ); $this->add( ComingSoonRequestHandler::class )->addArgument( ComingSoonHelper::class ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js index 19f9ce4255c..cfef43102a9 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/launch-your-store.spec.js @@ -212,24 +212,11 @@ test.describe( await page.goto( '/wp-admin/admin.php?page=wc-admin' ); await expect( - page.getByRole( 'button', { + page.getByRole( 'menuitem', { name: 'Store coming soon', exact: true, } ) ).toBeVisible(); - - page.getByRole( 'button', { - name: 'Store coming soon', - exact: true, - } ).click(); - - await expect( - page.getByText( 'Manage site visibility' ) - ).toBeVisible(); - - await expect( - page.getByText( 'Customize "Coming soon" page' ) - ).toBeVisible(); } ); test( 'Homescreen badge coming soon entire store', async ( { @@ -257,24 +244,11 @@ test.describe( await page.goto( '/wp-admin/admin.php?page=wc-admin' ); await expect( - page.getByRole( 'button', { - name: 'Site coming soon', + page.getByRole( 'menuitem', { + name: 'Coming soon', exact: true, } ) ).toBeVisible(); - - page.getByRole( 'button', { - name: 'Site coming soon', - exact: true, - } ).click(); - - await expect( - page.getByText( 'Manage site visibility' ) - ).toBeVisible(); - - await expect( - page.getByText( 'Customize "Coming soon" page' ) - ).toBeVisible(); } ); test( 'Homescreen badge live', async ( { page, baseURL } ) => { @@ -299,24 +273,11 @@ test.describe( await page.goto( '/wp-admin/admin.php?page=wc-admin' ); await expect( - page.getByRole( 'button', { + page.getByRole( 'menuitem', { name: 'Live', exact: true, } ) ).toBeVisible(); - - page.getByRole( 'button', { - name: 'Live', - exact: true, - } ).click(); - - await expect( - page.getByText( 'Manage site visibility' ) - ).toBeVisible(); - - await expect( - page.getByText( 'Customize "Coming soon" page' ) - ).toBeHidden(); } ); } ); From d7682504d95f982a9b40ddaa1362ebf1778e3fea Mon Sep 17 00:00:00 2001 From: RJ <27843274+rjchow@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:13:17 +0800 Subject: [PATCH 029/185] fix: replaced apostrophes for WooCommerce Admin JS strings in Homescreen & Core Profiler (#50776) --- .../client/core-profiler/pages/BusinessInfo.tsx | 8 ++++---- .../core-profiler/pages/BusinessLocation.tsx | 2 +- .../client/core-profiler/pages/IntroOptIn.tsx | 2 +- .../client/core-profiler/pages/UserProfile.tsx | 12 ++++++------ .../pages/tests/business-info.test.tsx | 2 +- .../pages/tests/user-profile.test.tsx | 4 ++-- .../core-profiler/utils/get-loader-stage-meta.tsx | 4 ++-- .../client/dashboard/components/cart-modal.js | 4 ++-- .../client/error-boundary/index.tsx | 2 +- .../client/guided-tours/shipping-tour.tsx | 14 +++++++------- .../homescreen/activity-panel/orders/index.js | 2 +- .../woocommerce-admin/client/homescreen/layout.js | 2 +- .../components/useSendMagicLink.tsx | 6 +++--- .../woocommerce-admin/client/inbox-panel/index.js | 2 +- .../pages/launch-store-success/WhatsNext.tsx | 4 ++-- .../pages/launch-store-success/index.tsx | 4 ++-- .../settings/components/confirmation-modal.jsx | 2 +- .../client/launch-your-store/tour/index.tsx | 4 ++-- .../components/Setup/Configure.js | 2 +- .../load-sample-product-confirm-modal.tsx | 2 +- .../fills/import-products/test/index.tsx | 2 +- .../task-lists/fills/products/test/index.tsx | 2 +- .../client/task-lists/fills/shipping/index.js | 2 +- .../task-lists/fills/tax/components/partners.tsx | 2 +- .../client/task-lists/fills/tax/index.tsx | 2 +- .../progress-title/default-progress-title.tsx | 6 +++--- .../test/default-progress-title.test.tsx | 12 ++++++------ .../task-lists/reminder-bar/reminder-bar.tsx | 2 +- .../components/task-headers/launch-your-store.tsx | 2 +- .../components/task-headers/store-details.js | 2 +- .../task-headers/woocommerce-payments.js | 2 +- .../components/task-list-completed-header.tsx | 2 +- .../components/task-list-completed.tsx | 2 +- .../onboarding-homepage-notice/index.js | 2 +- .../onboarding-tax-notice/index.js | 2 +- plugins/woocommerce-admin/package.json | 2 +- plugins/woocommerce/changelog/fix-apostrophes | 4 ++++ .../tests/activate-and-setup/core-profiler.spec.js | 10 +++++----- 38 files changed, 74 insertions(+), 70 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-apostrophes diff --git a/plugins/woocommerce-admin/client/core-profiler/pages/BusinessInfo.tsx b/plugins/woocommerce-admin/client/core-profiler/pages/BusinessInfo.tsx index 8a682cee24a..7d28a8e1395 100644 --- a/plugins/woocommerce-admin/client/core-profiler/pages/BusinessInfo.tsx +++ b/plugins/woocommerce-admin/client/core-profiler/pages/BusinessInfo.tsx @@ -90,7 +90,7 @@ export const selectIndustryMapping = { 'woocommerce' ), im_setting_up_a_store_for_a_client: __( - "Which industry is your client's business in?", + 'Which industry is your client’s business in?', 'woocommerce' ), }; @@ -238,7 +238,7 @@ export const BusinessInfo = ( { 'woocommerce' ) } subTitle={ __( - "We'll use this information to help you set up payments, shipping, and taxes, as well as recommending the best theme for your store.", + 'We’ll use this information to help you set up payments, shipping, and taxes, as well as recommending the best theme for your store.', 'woocommerce' ) } /> @@ -268,7 +268,7 @@ export const BusinessInfo = ( { />

{ __( - "Don't worry — you can always change it later!", + 'Don’t worry — you can always change it later!', 'woocommerce' ) }

@@ -390,7 +390,7 @@ export const BusinessInfo = ( { { createInterpolateElement( __( // translators: first tag is filled with the country name detected by geolocation, second tag is the country name selected by the user - "It looks like you're located in . Are you sure you want to create a store in ?", + 'It looks like you’re located in . Are you sure you want to create a store in ?', 'woocommerce' ), { diff --git a/plugins/woocommerce-admin/client/core-profiler/pages/BusinessLocation.tsx b/plugins/woocommerce-admin/client/core-profiler/pages/BusinessLocation.tsx index 71b7b3676e4..ab0160ddf09 100644 --- a/plugins/woocommerce-admin/client/core-profiler/pages/BusinessLocation.tsx +++ b/plugins/woocommerce-admin/client/core-profiler/pages/BusinessLocation.tsx @@ -45,7 +45,7 @@ export const BusinessLocation = ( { 'woocommerce' ) } subTitle={ __( - "We'll use this information to help you set up payments, shipping, and taxes.", + 'We’ll use this information to help you set up payments, shipping, and taxes.', 'woocommerce' ) } /> diff --git a/plugins/woocommerce-admin/client/core-profiler/pages/IntroOptIn.tsx b/plugins/woocommerce-admin/client/core-profiler/pages/IntroOptIn.tsx index aa795e175c4..e8861744aaa 100644 --- a/plugins/woocommerce-admin/client/core-profiler/pages/IntroOptIn.tsx +++ b/plugins/woocommerce-admin/client/core-profiler/pages/IntroOptIn.tsx @@ -45,7 +45,7 @@ export const IntroOptIn = ( { title={ __( 'Welcome to Woo!', 'woocommerce' ) } subTitle={ interpolateComponents( { mixedString: __( - "It's great to have you here with us! We'll be guiding you through the setup process – first, answer a few questions to tailor your experience.", + 'It’s great to have you here with us! We’ll be guiding you through the setup process – first, answer a few questions to tailor your experience.', 'woocommerce' ), components: { diff --git a/plugins/woocommerce-admin/client/core-profiler/pages/UserProfile.tsx b/plugins/woocommerce-admin/client/core-profiler/pages/UserProfile.tsx index 87fd87058d8..b7980c993d4 100644 --- a/plugins/woocommerce-admin/client/core-profiler/pages/UserProfile.tsx +++ b/plugins/woocommerce-admin/client/core-profiler/pages/UserProfile.tsx @@ -20,32 +20,32 @@ import { MultipleSelector } from '../components/multiple-selector/multiple-selec const businessOptions = [ { - title: __( "I'm just starting my business", 'woocommerce' ), + title: __( 'I’m just starting my business', 'woocommerce' ), value: 'im_just_starting_my_business' as const, }, { - title: __( "I'm already selling", 'woocommerce' ), + title: __( 'I’m already selling', 'woocommerce' ), value: 'im_already_selling' as const, }, { - title: __( "I'm setting up a store for a client", 'woocommerce' ), + title: __( 'I’m setting up a store for a client', 'woocommerce' ), value: 'im_setting_up_a_store_for_a_client' as const, }, ]; const sellingOnlineOptions = [ { - label: __( "Yes, I'm selling online", 'woocommerce' ), + label: __( 'Yes, I’m selling online', 'woocommerce' ), value: 'yes_im_selling_online' as const, key: 'yes_im_selling_online' as const, }, { - label: __( "No, I'm selling offline", 'woocommerce' ), + label: __( 'No, I’m selling offline', 'woocommerce' ), value: 'no_im_selling_offline' as const, key: 'no_im_selling_offline' as const, }, { - label: __( "I'm selling both online and offline", 'woocommerce' ), + label: __( 'I’m selling both online and offline', 'woocommerce' ), value: 'im_selling_both_online_and_offline' as const, key: 'im_selling_both_online_and_offline' as const, }, diff --git a/plugins/woocommerce-admin/client/core-profiler/pages/tests/business-info.test.tsx b/plugins/woocommerce-admin/client/core-profiler/pages/tests/business-info.test.tsx index cc00ca11ce8..e5618147188 100644 --- a/plugins/woocommerce-admin/client/core-profiler/pages/tests/business-info.test.tsx +++ b/plugins/woocommerce-admin/client/core-profiler/pages/tests/business-info.test.tsx @@ -94,7 +94,7 @@ describe( 'BusinessInfo', () => { 'im_setting_up_a_store_for_a_client'; render( ); expect( - screen.getByText( /Which industry is your client's business in?/i ) + screen.getByText( /Which industry is your client’s business in?/i ) ).toBeInTheDocument(); } ); diff --git a/plugins/woocommerce-admin/client/core-profiler/pages/tests/user-profile.test.tsx b/plugins/woocommerce-admin/client/core-profiler/pages/tests/user-profile.test.tsx index b7382b672aa..fe888367891 100644 --- a/plugins/woocommerce-admin/client/core-profiler/pages/tests/user-profile.test.tsx +++ b/plugins/woocommerce-admin/client/core-profiler/pages/tests/user-profile.test.tsx @@ -50,7 +50,7 @@ describe( 'UserProfile', () => { // @ts-ignore render( ); const radioInput = screen.getByLabelText< HTMLInputElement >( - "I'm already selling" + 'I’m already selling' ); // Replace with the label of your radio button // Perform the radio button selection @@ -65,7 +65,7 @@ describe( 'UserProfile', () => { expect( onlineSellingQuestion ).toBeInTheDocument(); } ); - it( 'should show online selling question when choosing "Yes, I\'m selling online"', () => { + it( 'should show online selling question when choosing "Yes, I’m selling online"', () => { render( // @ts-ignore , paragraphs: [ { @@ -42,7 +42,7 @@ const LayoutStage = { }; const DevelopingStage = { - title: __( "Woo! Let's get your features ready", 'woocommerce' ), + title: __( 'Woo! Let’s get your features ready', 'woocommerce' ), image: loader-developng, paragraphs: [ { diff --git a/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js b/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js index 6854fa9e236..05486e5b27e 100644 --- a/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js +++ b/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js @@ -137,7 +137,7 @@ class CartModal extends Component {

{ __( - "You won't have access to this functionality until the extensions have been purchased and installed.", + 'You won’t have access to this functionality until the extensions have been purchased and installed.', 'woocommerce' ) }

@@ -148,7 +148,7 @@ class CartModal extends Component { isBusy={ purchaseLaterButtonBusy } onClick={ () => this.onClickPurchaseLater() } > - { __( "I'll do it later", 'woocommerce' ) } + { __( 'I’ll do it later', 'woocommerce' ) } diff --git a/plugins/woocommerce-admin/client/task-lists/fills/tax/index.tsx b/plugins/woocommerce-admin/client/task-lists/fills/tax/index.tsx index 23e5952d0ce..c4c95cdb95e 100644 --- a/plugins/woocommerce-admin/client/task-lists/fills/tax/index.tsx +++ b/plugins/woocommerce-admin/client/task-lists/fills/tax/index.tsx @@ -122,7 +122,7 @@ export const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => { createNotice( 'success', __( - "You're awesome! One less item on your to-do list ✅", + 'You’re awesome! One less item on your to-do list ✅', 'woocommerce' ) ); diff --git a/plugins/woocommerce-admin/client/task-lists/progress-title/default-progress-title.tsx b/plugins/woocommerce-admin/client/task-lists/progress-title/default-progress-title.tsx index 45c06e34ac1..ca2be82ba3e 100644 --- a/plugins/woocommerce-admin/client/task-lists/progress-title/default-progress-title.tsx +++ b/plugins/woocommerce-admin/client/task-lists/progress-title/default-progress-title.tsx @@ -56,12 +56,12 @@ export const DefaultProgressTitle: React.FC< DefaultProgressTitleProps > = ( { : __( 'Welcome to your store', 'woocommerce' ); } if ( completedCount <= 3 ) { - return __( "Let's get you started", 'woocommerce' ) + ' 🚀'; + return __( 'Let’s get you started', 'woocommerce' ) + ' 🚀'; } if ( completedCount > 3 && completedCount < 6 ) { - return __( "You're on the right track", 'woocommerce' ); + return __( 'You’re on the right track', 'woocommerce' ); } - return __( "You're almost there", 'woocommerce' ); + return __( 'You’re almost there', 'woocommerce' ); }, [ completedCount, hasVisitedTasks, tasksCount ] ); if ( loading ) { diff --git a/plugins/woocommerce-admin/client/task-lists/progress-title/test/default-progress-title.test.tsx b/plugins/woocommerce-admin/client/task-lists/progress-title/test/default-progress-title.test.tsx index 4dd25686444..4ab493c3d35 100644 --- a/plugins/woocommerce-admin/client/task-lists/progress-title/test/default-progress-title.test.tsx +++ b/plugins/woocommerce-admin/client/task-lists/progress-title/test/default-progress-title.test.tsx @@ -49,7 +49,7 @@ describe( 'default-progress-title', () => { ).toBeInTheDocument(); } ); - it( 'should render "Let\'s get you started" when has task visited and task completed count <= 3', () => { + it( 'should render "Let’s get you started" when has task visited and task completed count <= 3', () => { ( useSelect as jest.Mock ).mockImplementation( ( fn ) => fn( () => ( { getTaskList: () => ( { @@ -60,11 +60,11 @@ describe( 'default-progress-title', () => { ); render( ); expect( - screen.getByText( "Let's get you started", { exact: false } ) + screen.getByText( 'Let’s get you started', { exact: false } ) ).toBeInTheDocument(); } ); - it( 'should render "You\'re on the right track" when has task visited and task completed count > 3', () => { + it( 'should render "You’re on the right track" when has task visited and task completed count > 3', () => { ( useSelect as jest.Mock ).mockImplementation( ( fn ) => fn( () => ( { getTaskList: () => ( { @@ -81,11 +81,11 @@ describe( 'default-progress-title', () => { ); render( ); expect( - screen.getByText( "You're on the right track", { exact: false } ) + screen.getByText( 'You’re on the right track', { exact: false } ) ).toBeInTheDocument(); } ); - it( 'should render "You\'re almost there" when has task visited and task completed count > 5', () => { + it( 'should render "You’re almost there" when has task visited and task completed count > 5', () => { ( useSelect as jest.Mock ).mockImplementation( ( fn ) => fn( () => ( { getTaskList: () => ( { @@ -104,7 +104,7 @@ describe( 'default-progress-title', () => { ); render( ); expect( - screen.getByText( "You're almost there", { exact: false } ) + screen.getByText( 'You’re almost there', { exact: false } ) ).toBeInTheDocument(); } ); } ); diff --git a/plugins/woocommerce-admin/client/task-lists/reminder-bar/reminder-bar.tsx b/plugins/woocommerce-admin/client/task-lists/reminder-bar/reminder-bar.tsx index 1a96b202e3c..64bb0e04d76 100644 --- a/plugins/woocommerce-admin/client/task-lists/reminder-bar/reminder-bar.tsx +++ b/plugins/woocommerce-admin/client/task-lists/reminder-bar/reminder-bar.tsx @@ -52,7 +52,7 @@ const ReminderText: React.FC< ReminderTextProps > = ( { ) : /* translators: 1: remaining tasks count */ __( - "🚀 You're doing great! {{strongText}}%1$d steps left{{/strongText}} to get your store up and running. {{setupLink}}Continue setup{{/setupLink}}", + '🚀 You’re doing great! {{strongText}}%1$d steps left{{/strongText}} to get your store up and running. {{setupLink}}Continue setup{{/setupLink}}', 'woocommerce' ); diff --git a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/launch-your-store.tsx b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/launch-your-store.tsx index bbe78e5a4fb..355e0682eb0 100644 --- a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/launch-your-store.tsx +++ b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/launch-your-store.tsx @@ -34,7 +34,7 @@ const LaunchYourStoreHeader = ( {

{ __( - "It's time to celebrate – you're ready to launch your store! Woo! Hit the button to preview your store and make it public.", + 'It’s time to celebrate – you’re ready to launch your store! Woo! Hit the button to preview your store and make it public.', 'woocommerce' ) }

diff --git a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/store-details.js b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/store-details.js index 67fc76a2442..c66eb139a6b 100644 --- a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/store-details.js +++ b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/store-details.js @@ -26,7 +26,7 @@ const StoreDetailsHeader = ( { task, goToTask } ) => {

{ __( - "Get your store up and running in no time. Add your store's address to set up shipping, tax and payments faster.", + 'Get your store up and running in no time. Add your store’s address to set up shipping, tax and payments faster.', 'woocommerce' ) }

diff --git a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/woocommerce-payments.js b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/woocommerce-payments.js index a6f21627e19..47fe2ffb4d6 100644 --- a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/woocommerce-payments.js +++ b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-headers/woocommerce-payments.js @@ -54,7 +54,7 @@ const WoocommercePaymentsHeader = ( { task, trackClick } ) => { className="svg-background" />
-

{ __( "It's time to get paid", 'woocommerce' ) }

+

{ __( 'It’s time to get paid', 'woocommerce' ) }

{ incentive?.task_header_content ? (

{ __( - "You've completed store setup", + 'You’ve completed store setup', 'woocommerce' ) } diff --git a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-list-completed.tsx b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-list-completed.tsx index d19bd0806c3..a91359b9b4c 100644 --- a/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-list-completed.tsx +++ b/plugins/woocommerce-admin/client/task-lists/setup-task-list/components/task-list-completed.tsx @@ -33,7 +33,7 @@ export const TaskListCompleted = ( { Completed

{ __( - "You've completed store setup", + 'You’ve completed store setup', 'woocommerce' ) }

diff --git a/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-homepage-notice/index.js b/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-homepage-notice/index.js index c12455cbf8b..d4fee7e468c 100644 --- a/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-homepage-notice/index.js +++ b/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-homepage-notice/index.js @@ -70,7 +70,7 @@ const onboardingHomepageNotice = () => { dispatch( 'core/notices' ).removeNotice( 'SAVE_POST_NOTICE_ID' ); dispatch( 'core/notices' ).createSuccessNotice( - __( "🏠 Nice work creating your store's homepage!", 'woocommerce' ), + __( '🏠 Nice work creating your store’s homepage!', 'woocommerce' ), { id: 'WOOCOMMERCE_ONBOARDING_HOME_PAGE_NOTICE', type: notificationType, diff --git a/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-tax-notice/index.js b/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-tax-notice/index.js index 5b94d57b28b..8cf91d192a0 100644 --- a/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-tax-notice/index.js +++ b/plugins/woocommerce-admin/client/wp-admin-scripts/onboarding-tax-notice/index.js @@ -41,7 +41,7 @@ const showTaxCompletionNotice = () => { saveButton.classList.add( 'has-tax' ); dispatch( 'core/notices' ).createSuccessNotice( - __( "You've added your first tax rate!", 'woocommerce' ), + __( 'You’ve added your first tax rate!', 'woocommerce' ), { id: 'WOOCOMMERCE_ONBOARDING_TAX_NOTICE', actions: [ diff --git a/plugins/woocommerce-admin/package.json b/plugins/woocommerce-admin/package.json index 3106b273088..436ea164243 100644 --- a/plugins/woocommerce-admin/package.json +++ b/plugins/woocommerce-admin/package.json @@ -22,7 +22,7 @@ "lint": "pnpm --if-present '/^lint:lang:.*$/'", "lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'", "lint:fix:lang:css": "stylelint '**/*.scss' --fix --ip 'storybook/wordpress'", - "lint:fix:lang:js": "pnpm lint:js --fix --ext=js,ts,tsx", + "lint:fix:lang:js": "pnpm lint:lang:js --fix --ext=js,ts,tsx", "lint:lang:css": "stylelint '**/*.scss'", "lint:lang:js": "eslint ./client --ext=js,ts,tsx", "test:js": "jest --config client/jest.config.js", diff --git a/plugins/woocommerce/changelog/fix-apostrophes b/plugins/woocommerce/changelog/fix-apostrophes new file mode 100644 index 00000000000..4651d29074b --- /dev/null +++ b/plugins/woocommerce/changelog/fix-apostrophes @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Changed instances of prime marks inappropriately used when apostrophes are supposed to be used for some parts of WC Admin JS/TS/TSX files diff --git a/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js index 9537c6a5e34..0f4204f2075 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js @@ -29,7 +29,7 @@ test.describe( 'Store owner can complete the core profiler', () => { } ) ).toBeVisible(); await page - .getByRole( 'radio', { name: "I'm just starting my business" } ) + .getByRole( 'radio', { name: 'I’m just starting my business' } ) .first() .click(); await page.getByRole( 'button', { name: 'Continue' } ).click(); @@ -175,12 +175,12 @@ test.describe( 'Store owner can complete the core profiler', () => { } ) ).toBeVisible(); await page - .getByRole( 'radio', { name: "I'm already selling" } ) + .getByRole( 'radio', { name: 'I’m already selling' } ) .first() .click(); await page.getByLabel( 'Select an option' ).click(); await page - .getByRole( 'option', { name: "No, I'm selling offline" } ) + .getByRole( 'option', { name: 'No, I’m selling offline' } ) .click(); await page.getByRole( 'button', { name: 'Continue' } ).click(); } ); @@ -282,14 +282,14 @@ test.describe( 'Store owner can complete the core profiler', () => { await expect .soft( page.getByRole( 'heading', { - name: "Woo! Let's get your features ready", + name: 'Woo! Let’s get your features ready', } ) ) .toBeVisible( { timeout: 30000 } ); await expect .soft( page.getByRole( 'heading', { - name: "Extending your store's capabilities", + name: 'Extending your store’s capabilities', } ) ) .toBeVisible( { timeout: 30000 } ); From 2a406c7e8aa040a454b3227151aeedbf59fad2fe Mon Sep 17 00:00:00 2001 From: Seghir Nadir Date: Tue, 20 Aug 2024 12:14:11 +0200 Subject: [PATCH 030/185] Update all blocks to V3 (#48720) * Update all blocks to V3 * remove explicit version set in shared config blocks * update styling for Cart/Checkout in iframe * test: fix block e2e tests * test: fix attribute filter e2e tests * test: fix product collection e2e tests * test: fix product on sale e2e test * test: fix rating filter e2e tests * test: fix review e2e tests * test: fix stock e2e tests * test: fix preview button test * fix: product on sale wrapper * test: fix insertBlockByShortcut in iframe * test: fix core e2e tests * chore: changelog * test: typo * test: update PC e2e tests * add test to make sure iframe canvas is loaded * fix syntax error * Update plugins/woocommerce-blocks/tests/e2e/tests/basic.block_theme.spec.ts Co-authored-by: Bart Kalisz --------- Co-authored-by: Tung Du Co-authored-by: Bart Kalisz --- .../changelog/add-upgrade-blocks-to-v3 | 4 ++ .../block.json.mustache | 2 +- .../changelog/add-upgrade-blocks-to-v3 | 4 ++ .../src/blocks/generic/checkbox/block.json | 14 +++-- .../src/blocks/generic/collapsible/block.json | 4 +- .../src/blocks/generic/conditional/block.json | 4 +- .../generic/linked-product-list/block.json | 15 ++++-- .../src/blocks/generic/number/block.json | 10 ++-- .../src/blocks/generic/pricing/block.json | 13 +++-- .../src/blocks/generic/radio/block.json | 14 +++-- .../generic/section-description/block.json | 10 ++-- .../src/blocks/generic/section/block.json | 16 ++++-- .../src/blocks/generic/select/block.json | 13 +++-- .../generic/subsection-description/block.json | 10 ++-- .../src/blocks/generic/subsection/block.json | 16 ++++-- .../src/blocks/generic/tab/block.json | 14 +++-- .../src/blocks/generic/taxonomy/block.json | 13 +++-- .../src/blocks/generic/text-area/block.json | 26 ++++++--- .../src/blocks/generic/text/block.json | 13 +++-- .../src/blocks/generic/toggle/block.json | 14 +++-- .../product-fields/attributes/block.json | 13 +++-- .../catalog-visibility/block.json | 16 ++++-- .../custom-fields-toggle/block.json | 10 ++-- .../product-fields/custom-fields/block.json | 10 ++-- .../product-fields/description/block.json | 9 ++-- .../product-fields/downloads/block.json | 13 +++-- .../blocks/product-fields/images/block.json | 15 ++++-- .../product-fields/inventory-email/block.json | 11 ++-- .../inventory-quantity/block.json | 14 +++-- .../product-fields/inventory-sku/block.json | 13 +++-- .../src/blocks/product-fields/name/block.json | 10 ++-- .../notice-edit-single-variation/block.json | 9 ++-- .../notice-has-variations/block.json | 9 ++-- .../blocks/product-fields/password/block.json | 9 ++-- .../block.json | 10 ++-- .../product-fields/product-list/block.json | 12 +++-- .../product-fields/regular-price/block.json | 13 +++-- .../product-fields/sale-price/block.json | 13 +++-- .../product-fields/schedule-sale/block.json | 14 +++-- .../product-fields/shipping-class/block.json | 15 ++++-- .../shipping-dimensions/block.json | 14 +++-- .../blocks/product-fields/summary/block.json | 19 +++++-- .../src/blocks/product-fields/tag/block.json | 14 +++-- .../product-fields/variation-items/block.json | 13 +++-- .../variation-options/block.json | 14 +++-- .../add-to-cart-form/block.json | 12 +++-- .../average-rating/block.json | 13 +++-- .../product-elements/average-rating/index.tsx | 1 + .../blocks/product-elements/button/block.json | 23 +++++--- .../blocks/product-elements/button/index.tsx | 1 + .../blocks/product-elements/image/index.ts | 1 - .../blocks/product-elements/price/index.tsx | 1 - .../product-details/block.json | 8 +-- .../product-image-gallery/block.json | 14 +++-- .../product-elements/product-meta/block.json | 14 +++-- .../product-reviews/block.json | 12 +++-- .../rating-counter/block.json | 18 +++++-- .../product-elements/rating-counter/index.tsx | 1 + .../product-elements/rating-stars/block.json | 19 ++++--- .../product-elements/rating-stars/index.tsx | 1 + .../blocks/product-elements/rating/block.json | 14 +++-- .../related-products/block.json | 14 +++-- .../product-elements/sale-badge/index.ts | 1 - .../blocks/product-elements/shared/config.tsx | 1 + .../blocks/product-elements/sku/index.tsx | 1 - .../product-elements/stock-indicator/index.ts | 1 - .../blocks/product-elements/summary/index.ts | 1 - .../blocks/product-elements/title/index.ts | 1 - .../js/blocks/active-filters/block.json | 8 +-- .../assets/js/blocks/active-filters/index.tsx | 1 + .../js/blocks/attribute-filter/block.json | 8 +-- .../js/blocks/attribute-filter/index.tsx | 1 + .../assets/js/blocks/breadcrumbs/block.json | 13 +++-- .../assets/js/blocks/cart/editor.scss | 2 + .../assets/js/blocks/cart/index.js | 1 + .../block.json | 8 +-- .../cart-cross-sells-block/block.json | 8 +-- .../cart-cross-sells-products/block.json | 8 +-- .../cart-express-payment-block/block.json | 8 +-- .../inner-blocks/cart-items-block/block.json | 8 +-- .../cart-line-items-block/block.json | 8 +-- .../cart-order-summary-block/block.json | 8 +-- .../cart-order-summary-coupon-form/block.json | 8 +-- .../cart-order-summary-discount/block.json | 8 +-- .../cart-order-summary-fee/block.json | 8 +-- .../cart-order-summary-heading/block.json | 8 +-- .../cart-order-summary-shipping/block.json | 8 +-- .../cart-order-summary-subtotal/block.json | 8 +-- .../cart-order-summary-taxes/block.json | 8 +-- .../cart-order-summary-totals/block.json | 8 +-- .../inner-blocks/cart-totals-block/block.json | 8 +-- .../inner-blocks/empty-cart-block/block.json | 12 +++-- .../inner-blocks/filled-cart-block/block.json | 12 +++-- .../proceed-to-checkout-block/block.json | 8 +-- .../js/blocks/catalog-sorting/block.json | 8 +-- .../assets/js/blocks/checkout/block.json | 12 +++-- .../js/blocks/checkout/form-step/editor.scss | 4 +- .../checkout-actions-block/block.json | 8 +-- .../block.json | 8 +-- .../checkout-billing-address-block/block.json | 8 +-- .../block.json | 8 +-- .../checkout-express-payment-block/block.json | 8 +-- .../checkout-fields-block/block.json | 8 +-- .../checkout-order-note-block/block.json | 8 +-- .../checkout-order-summary-block/block.json | 8 +-- .../block.json | 8 +-- .../block.json | 8 +-- .../block.json | 8 +-- .../checkout-order-summary-fee/block.json | 8 +-- .../block.json | 8 +-- .../block.json | 8 +-- .../checkout-order-summary-taxes/block.json | 8 +-- .../checkout-order-summary-totals/block.json | 8 +-- .../checkout-payment-block/block.json | 8 +-- .../checkout-pickup-options-block/block.json | 8 +-- .../block.json | 8 +-- .../checkout-shipping-method-block/block.json | 8 +-- .../block.json | 8 +-- .../checkout-terms-block/block.json | 8 +-- .../checkout-totals-block/block.json | 8 +-- .../js/blocks/classic-shortcode/block.json | 13 +++-- .../js/blocks/classic-shortcode/index.tsx | 1 + .../js/blocks/classic-template/index.tsx | 2 +- .../assets/js/blocks/coming-soon/index.tsx | 2 +- .../js/blocks/customer-account/block.json | 9 ++-- .../featured-category/block.json | 4 +- .../featured-product/block.json | 13 +++-- .../js/blocks/filter-wrapper/block.json | 8 +-- .../js/blocks/handpicked-products/block.json | 14 +++-- .../assets/js/blocks/mini-cart/block.json | 8 +-- .../mini-cart/mini-cart-contents/index.tsx | 2 +- .../empty-mini-cart-contents-block/block.json | 8 +-- .../block.json | 8 +-- .../mini-cart-cart-button-block/block.json | 8 +-- .../block.json | 4 +- .../mini-cart-footer-block/block.json | 8 +-- .../mini-cart-items-block/block.json | 8 +-- .../mini-cart-products-table-block/block.json | 8 +-- .../block.json | 8 +-- .../mini-cart-title-block/block.json | 8 +-- .../block.json | 8 +-- .../mini-cart-title-label-block/block.json | 8 +-- .../additional-fields-wrapper/block.json | 2 +- .../additional-fields/block.json | 13 +++-- .../additional-information/block.json | 13 +++-- .../billing-address/block.json | 13 +++-- .../billing-wrapper/block.json | 13 +++-- .../downloads-wrapper/block.json | 13 +++-- .../order-confirmation/downloads/block.json | 13 +++-- .../shipping-address/block.json | 13 +++-- .../shipping-wrapper/block.json | 13 +++-- .../order-confirmation/status/block.json | 13 +++-- .../order-confirmation/summary/block.json | 13 +++-- .../totals-wrapper/block.json | 13 +++-- .../order-confirmation/totals/block.json | 13 +++-- .../js/blocks/page-content-wrapper/block.json | 8 +-- .../assets/js/blocks/price-filter/block.json | 8 +-- .../js/blocks/product-best-sellers/block.json | 13 +++-- .../js/blocks/product-categories/block.json | 21 +++++--- .../js/blocks/product-category/block.json | 13 +++-- .../js/blocks/product-collection/block.json | 15 ++++-- .../js/blocks/product-filter/block.json | 16 ++++-- .../inner-blocks/active-filters/block.json | 16 ++++-- .../inner-blocks/attribute-filter/block.json | 17 ++++-- .../inner-blocks/clear-button/block.json | 13 +++-- .../inner-blocks/price-filter/block.json | 17 ++++-- .../inner-blocks/rating-filter/block.json | 17 ++++-- .../inner-blocks/stock-filter/block.json | 19 +++++-- .../blocks/product-filters-overlay/block.json | 8 +-- .../js/blocks/product-filters/block.json | 6 ++- .../js/blocks/product-gallery/block.json | 14 +++-- .../block.json | 30 +++++++---- .../product-gallery-large-image/block.json | 28 ++++++---- .../product-gallery-pager/block.json | 21 +++++--- .../product-gallery-thumbnails/block.json | 33 ++++++++---- .../assets/js/blocks/product-new/block.json | 13 +++-- .../js/blocks/product-on-sale/block.tsx | 8 +-- .../assets/js/blocks/product-on-sale/index.js | 1 + .../blocks/product-results-count/block.json | 12 +++-- .../assets/js/blocks/product-search/index.tsx | 1 + .../assets/js/blocks/product-tag/block.json | 13 +++-- .../js/blocks/product-template/block.json | 13 +++-- .../js/blocks/product-top-rated/block.json | 13 +++-- .../blocks/products-by-attribute/block.json | 18 +++++-- .../blocks/products/all-products/block.json | 11 ++-- .../assets/js/blocks/rating-filter/block.json | 8 +-- .../js/blocks/reviews/all-reviews/index.tsx | 2 +- .../reviews/reviews-by-category/index.tsx | 2 +- .../reviews/reviews-by-product/index.js | 2 +- .../js/blocks/single-product/block.json | 17 +++--- .../assets/js/blocks/stock-filter/block.json | 8 +-- .../assets/js/blocks/store-notices/block.json | 13 +++-- .../all-reviews.block_theme.spec.ts | 5 +- .../attribute-filter.block_theme.spec.ts | 14 ++--- .../tests/e2e/tests/basic.block_theme.spec.ts | 5 ++ .../featured-category.block_theme.spec.ts | 6 +-- .../featured-product.block_theme.spec.ts | 6 +-- .../page-content-wrapper.block_theme.spec.ts | 2 +- .../price-filter.block_theme.spec.ts | 8 +-- .../product-collection.block_theme.spec.ts | 54 ++++++++++--------- .../product-collection.page.ts | 16 +++--- .../rating-filter.block_theme.spec.ts | 14 ++--- .../reviews-by-category.block_theme.spec.ts | 8 +-- .../reviews-by-product.block_theme.spec.ts | 10 ++-- .../stock-filter.block_theme.spec.ts | 10 ++-- .../changelog/add-upgrade-blocks-to-v3 | 4 ++ .../e2e-pw/tests/shopper/mini-cart.spec.js | 13 +++-- .../shopper/product-tags-attributes.spec.js | 14 ++--- .../woocommerce/tests/e2e-pw/utils/editor.js | 2 +- 209 files changed, 1414 insertions(+), 699 deletions(-) create mode 100644 packages/js/extend-cart-checkout-block/changelog/add-upgrade-blocks-to-v3 create mode 100644 packages/js/product-editor/changelog/add-upgrade-blocks-to-v3 create mode 100644 plugins/woocommerce/changelog/add-upgrade-blocks-to-v3 diff --git a/packages/js/extend-cart-checkout-block/changelog/add-upgrade-blocks-to-v3 b/packages/js/extend-cart-checkout-block/changelog/add-upgrade-blocks-to-v3 new file mode 100644 index 00000000000..def28ee9bcc --- /dev/null +++ b/packages/js/extend-cart-checkout-block/changelog/add-upgrade-blocks-to-v3 @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Update all blocks to use API Version 3. diff --git a/packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/block.json.mustache b/packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/block.json.mustache index 98553e8cae7..9a157b4c339 100644 --- a/packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/block.json.mustache +++ b/packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/block.json.mustache @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "{{slug}}/checkout-newsletter-subscription", "version": "2.0.0", "title": "Newsletter Subscription!", diff --git a/packages/js/product-editor/changelog/add-upgrade-blocks-to-v3 b/packages/js/product-editor/changelog/add-upgrade-blocks-to-v3 new file mode 100644 index 00000000000..def28ee9bcc --- /dev/null +++ b/packages/js/product-editor/changelog/add-upgrade-blocks-to-v3 @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Update all blocks to use API Version 3. diff --git a/packages/js/product-editor/src/blocks/generic/checkbox/block.json b/packages/js/product-editor/src/blocks/generic/checkbox/block.json index 49b4d26080f..8cd8ae0109a 100644 --- a/packages/js/product-editor/src/blocks/generic/checkbox/block.json +++ b/packages/js/product-editor/src/blocks/generic/checkbox/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-checkbox-field", "title": "Product checkbox control", "category": "woocommerce", "description": "A reusable checkbox for the product editor.", - "keywords": [ "products", "checkbox", "input" ], + "keywords": [ + "products", + "checkbox", + "input" + ], "textdomain": "default", "attributes": { "title": { @@ -38,5 +42,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/collapsible/block.json b/packages/js/product-editor/src/blocks/generic/collapsible/block.json index 8cf084538cf..08ef5803965 100644 --- a/packages/js/product-editor/src/blocks/generic/collapsible/block.json +++ b/packages/js/product-editor/src/blocks/generic/collapsible/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-collapsible", "title": "Collapsible", "category": "widgets", @@ -27,4 +27,4 @@ "lock": false, "__experimentalToolbar": false } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/conditional/block.json b/packages/js/product-editor/src/blocks/generic/conditional/block.json index 5afff2f5865..20b825c2f25 100644 --- a/packages/js/product-editor/src/blocks/generic/conditional/block.json +++ b/packages/js/product-editor/src/blocks/generic/conditional/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/conditional", "title": "Conditional", "category": "widgets", @@ -25,4 +25,4 @@ "lock": false, "__experimentalToolbar": false } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/linked-product-list/block.json b/packages/js/product-editor/src/blocks/generic/linked-product-list/block.json index 245876fc294..65aa7146e71 100644 --- a/packages/js/product-editor/src/blocks/generic/linked-product-list/block.json +++ b/packages/js/product-editor/src/blocks/generic/linked-product-list/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-linked-list-field", "title": "Linked product list", "category": "widgets", "description": "The linked product list.", - "keywords": [ "products", "linked", "list" ], + "keywords": [ + "products", + "linked", + "list" + ], "textdomain": "default", "attributes": { "property": { @@ -27,5 +31,8 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType", "isInSelectedTab" ] -} + "usesContext": [ + "postType", + "isInSelectedTab" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/number/block.json b/packages/js/product-editor/src/blocks/generic/number/block.json index c8fdbc69878..dada23bf4fb 100644 --- a/packages/js/product-editor/src/blocks/generic/number/block.json +++ b/packages/js/product-editor/src/blocks/generic/number/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-number-field", "title": "Product number control", "category": "woocommerce", "description": "A reusable number field for the product editor.", - "keywords": [ "products", "number", "input" ], + "keywords": [ + "products", + "number", + "input" + ], "textdomain": "default", "attributes": { "label": { @@ -52,4 +56,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/pricing/block.json b/packages/js/product-editor/src/blocks/generic/pricing/block.json index 1402b64c62f..b2f1b6eaff8 100644 --- a/packages/js/product-editor/src/blocks/generic/pricing/block.json +++ b/packages/js/product-editor/src/blocks/generic/pricing/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-pricing-field", "description": "A product price block with currency display.", "title": "Product pricing", "category": "widgets", - "keywords": [ "products", "price" ], + "keywords": [ + "products", + "price" + ], "textdomain": "default", "attributes": { "property": { @@ -32,5 +35,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/radio/block.json b/packages/js/product-editor/src/blocks/generic/radio/block.json index d480795cf9e..45dc7f7d084 100644 --- a/packages/js/product-editor/src/blocks/generic/radio/block.json +++ b/packages/js/product-editor/src/blocks/generic/radio/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-radio-field", "title": "Product radio control", "category": "woocommerce", "description": "The product radio.", - "keywords": [ "products", "radio", "input" ], + "keywords": [ + "products", + "radio", + "input" + ], "textdomain": "default", "attributes": { "title": { @@ -39,5 +43,7 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/section-description/block.json b/packages/js/product-editor/src/blocks/generic/section-description/block.json index a31b7a0e3e6..dbccdf98913 100644 --- a/packages/js/product-editor/src/blocks/generic/section-description/block.json +++ b/packages/js/product-editor/src/blocks/generic/section-description/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-section-description", "title": "Product section description", "category": "woocommerce", "description": "The product section description.", - "keywords": [ "products", "section", "description" ], + "keywords": [ + "products", + "section", + "description" + ], "textdomain": "default", "attributes": { "content": { @@ -22,4 +26,4 @@ "lock": false, "__experimentalToolbar": false } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/section/block.json b/packages/js/product-editor/src/blocks/generic/section/block.json index 17a503bbdfd..b2d77ecfb43 100644 --- a/packages/js/product-editor/src/blocks/generic/section/block.json +++ b/packages/js/product-editor/src/blocks/generic/section/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-section", "title": "Product section", "category": "woocommerce", "description": "The product section.", - "keywords": [ "products", "section", "group" ], + "keywords": [ + "products", + "section", + "group" + ], "textdomain": "default", "attributes": { "title": { @@ -17,7 +21,11 @@ }, "blockGap": { "type": "string", - "enum": [ "unit-20", "unit-30", "unit-40" ], + "enum": [ + "unit-20", + "unit-30", + "unit-40" + ], "default": "unit-20" } }, @@ -31,4 +39,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/select/block.json b/packages/js/product-editor/src/blocks/generic/select/block.json index 620f3300fa2..738ebdcbfbd 100644 --- a/packages/js/product-editor/src/blocks/generic/select/block.json +++ b/packages/js/product-editor/src/blocks/generic/select/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-select-field", "title": "Product select field", "category": "woocommerce", "description": "A select field for use in the product editor.", - "keywords": [ "products", "select" ], + "keywords": [ + "products", + "select" + ], "textdomain": "default", "attributes": { "label": { @@ -60,5 +63,7 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/subsection-description/block.json b/packages/js/product-editor/src/blocks/generic/subsection-description/block.json index 58bb4dbc4ab..12c0712c53c 100644 --- a/packages/js/product-editor/src/blocks/generic/subsection-description/block.json +++ b/packages/js/product-editor/src/blocks/generic/subsection-description/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-subsection-description", "title": "Product subsection description", "category": "woocommerce", "description": "The product subsection description.", - "keywords": [ "products", "subsection", "description" ], + "keywords": [ + "products", + "subsection", + "description" + ], "textdomain": "default", "attributes": { "content": { @@ -22,4 +26,4 @@ "lock": false, "__experimentalToolbar": false } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/subsection/block.json b/packages/js/product-editor/src/blocks/generic/subsection/block.json index 6cbac142291..4dc20a21fd2 100644 --- a/packages/js/product-editor/src/blocks/generic/subsection/block.json +++ b/packages/js/product-editor/src/blocks/generic/subsection/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-subsection", "title": "Product subsection", "category": "woocommerce", "description": "The product subsection.", - "keywords": [ "products", "subsection", "group" ], + "keywords": [ + "products", + "subsection", + "group" + ], "textdomain": "default", "attributes": { "title": { @@ -17,7 +21,11 @@ }, "blockGap": { "type": "string", - "enum": [ "unit-20", "unit-30", "unit-40" ], + "enum": [ + "unit-20", + "unit-30", + "unit-40" + ], "default": "unit-20" } }, @@ -31,4 +39,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/tab/block.json b/packages/js/product-editor/src/blocks/generic/tab/block.json index 537e245ae57..20c1e649166 100644 --- a/packages/js/product-editor/src/blocks/generic/tab/block.json +++ b/packages/js/product-editor/src/blocks/generic/tab/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-tab", "title": "Product tab", "category": "woocommerce", "description": "The product tab.", - "keywords": [ "products", "tab", "group" ], + "keywords": [ + "products", + "tab", + "group" + ], "textdomain": "default", "attributes": { "id": { @@ -27,6 +31,8 @@ "providesContext": { "isInSelectedTab": "isSelected" }, - "usesContext": [ "selectedTab" ], + "usesContext": [ + "selectedTab" + ], "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/taxonomy/block.json b/packages/js/product-editor/src/blocks/generic/taxonomy/block.json index 69b5423852b..eeab0afc2c5 100644 --- a/packages/js/product-editor/src/blocks/generic/taxonomy/block.json +++ b/packages/js/product-editor/src/blocks/generic/taxonomy/block.json @@ -1,11 +1,13 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-taxonomy-field", "title": "Taxonomy", "category": "widgets", "description": "A block that displays a taxonomy field, allowing searching, selection, and creation of new items", - "keywords": [ "taxonomy" ], + "keywords": [ + "taxonomy" + ], "textdomain": "default", "attributes": { "slug": { @@ -51,5 +53,8 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType", "isInSelectedTab" ] -} + "usesContext": [ + "postType", + "isInSelectedTab" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/text-area/block.json b/packages/js/product-editor/src/blocks/generic/text-area/block.json index dd750f115d3..a9b16ba55f7 100644 --- a/packages/js/product-editor/src/blocks/generic/text-area/block.json +++ b/packages/js/product-editor/src/blocks/generic/text-area/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-text-area-field", "title": "Product textarea block", "category": "woocommerce", "description": "A text-area field for use in the product editor.", - "keywords": [ "textarea", "rich-text" ], + "keywords": [ + "textarea", + "rich-text" + ], "textdomain": "default", "attributes": { "property": { @@ -32,11 +35,19 @@ }, "align": { "type": "string", - "enum": [ "left", "center", "right", "justify" ] + "enum": [ + "left", + "center", + "right", + "justify" + ] }, "mode": { "type": "string", - "enum": [ "plain-text", "rich-text" ], + "enum": [ + "plain-text", + "rich-text" + ], "default": "rich-text" }, "allowedFormats": { @@ -56,7 +67,10 @@ }, "direction": { "type": "string", - "enum": [ "ltr", "rtl" ] + "enum": [ + "ltr", + "rtl" + ] } }, "supports": { @@ -68,4 +82,4 @@ "lock": false, "__experimentalToolbar": true } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/text/block.json b/packages/js/product-editor/src/blocks/generic/text/block.json index 4a2f037fe73..88314b4be5e 100644 --- a/packages/js/product-editor/src/blocks/generic/text/block.json +++ b/packages/js/product-editor/src/blocks/generic/text/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-text-field", "title": "Product text field", "category": "woocommerce", "description": "A text field for use in the product editor.", - "keywords": [ "products", "text" ], + "keywords": [ + "products", + "text" + ], "textdomain": "default", "attributes": { "label": { @@ -59,5 +62,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/generic/toggle/block.json b/packages/js/product-editor/src/blocks/generic/toggle/block.json index 5b41cb951c8..c26a3261401 100644 --- a/packages/js/product-editor/src/blocks/generic/toggle/block.json +++ b/packages/js/product-editor/src/blocks/generic/toggle/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-toggle-field", "title": "Product toggle control", "category": "woocommerce", "description": "The product toggle.", - "keywords": [ "products", "radio", "input" ], + "keywords": [ + "products", + "radio", + "input" + ], "textdomain": "default", "attributes": { "label": { @@ -48,5 +52,7 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/attributes/block.json b/packages/js/product-editor/src/blocks/product-fields/attributes/block.json index aed5dd2c121..7d69925cfdc 100644 --- a/packages/js/product-editor/src/blocks/product-fields/attributes/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/attributes/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-attributes-field", "title": "Product attributes", "category": "widgets", "description": "The product attributes.", - "keywords": [ "products", "attributes" ], + "keywords": [ + "products", + "attributes" + ], "textdomain": "default", "attributes": { "name": { @@ -22,6 +25,8 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "isInSelectedTab" ], + "usesContext": [ + "isInSelectedTab" + ], "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/catalog-visibility/block.json b/packages/js/product-editor/src/blocks/product-fields/catalog-visibility/block.json index b70967f8fa0..18b37da13e3 100644 --- a/packages/js/product-editor/src/blocks/product-fields/catalog-visibility/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/catalog-visibility/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-catalog-visibility-field", "description": "A checkbox to manage the catalog visibility of the product.", "title": "Product catalog visibility", "category": "widgets", - "keywords": [ "products", "catalog" ], + "keywords": [ + "products", + "catalog" + ], "textdomain": "default", "attributes": { "label": { @@ -14,7 +17,12 @@ }, "visibility": { "type": "string", - "enum": [ "visible", "catalog", "search", "hidden" ], + "enum": [ + "visible", + "catalog", + "search", + "hidden" + ], "default": "visible" } }, @@ -27,4 +35,4 @@ "lock": false, "__experimentalToolbar": false } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/custom-fields-toggle/block.json b/packages/js/product-editor/src/blocks/product-fields/custom-fields-toggle/block.json index ae2da4df2df..08aca1dcf79 100644 --- a/packages/js/product-editor/src/blocks/product-fields/custom-fields-toggle/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/custom-fields-toggle/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-custom-fields-toggle-field", "title": "Product custom fields toggle control", "category": "woocommerce", "description": "The product custom fields toggle.", - "keywords": [ "products", "custom", "fields" ], + "keywords": [ + "products", + "custom", + "fields" + ], "textdomain": "default", "attributes": { "label": { @@ -23,4 +27,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json b/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json index 73824721fe2..250d1b3a2db 100644 --- a/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/custom-fields/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-custom-fields", "title": "Product custom fields control", "category": "woocommerce", "description": "The product custom fields.", - "keywords": [ "products", "custom", "fields" ], + "keywords": [ + "products", + "custom", + "fields" + ], "textdomain": "default", "attributes": { "name": { @@ -22,4 +26,4 @@ "lock": false, "__experimentalToolbar": false } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/description/block.json b/packages/js/product-editor/src/blocks/product-fields/description/block.json index 3306eedfe1a..d8cbbbc98a7 100644 --- a/packages/js/product-editor/src/blocks/product-fields/description/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/description/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-description-field", "title": "Product description", "category": "woocommerce", "description": "The product description.", - "keywords": [ "products", "description" ], + "keywords": [ + "products", + "description" + ], "textdomain": "default", "attributes": { "__contentEditable": { @@ -22,4 +25,4 @@ "lock": false, "__experimentalToolbar": true } -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/downloads/block.json b/packages/js/product-editor/src/blocks/product-fields/downloads/block.json index 4f081aa6a28..a80b3ad6439 100644 --- a/packages/js/product-editor/src/blocks/product-fields/downloads/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/downloads/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-downloads-field", "title": "Product downloads", "category": "widgets", "description": "The product downloads.", - "keywords": [ "products", "downloads" ], + "keywords": [ + "products", + "downloads" + ], "textdomain": "default", "attributes": { "name": { @@ -23,5 +26,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/images/block.json b/packages/js/product-editor/src/blocks/product-fields/images/block.json index 12fe9006930..40885aeb5fc 100644 --- a/packages/js/product-editor/src/blocks/product-fields/images/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/images/block.json @@ -1,11 +1,16 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-images-field", "title": "Product images", "category": "widgets", "description": "The product images.", - "keywords": [ "products", "image", "images", "gallery" ], + "keywords": [ + "products", + "image", + "images", + "gallery" + ], "textdomain": "default", "attributes": { "mediaId": { @@ -38,5 +43,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/inventory-email/block.json b/packages/js/product-editor/src/blocks/product-fields/inventory-email/block.json index 5ac6cf80d4c..2b54ab1cb5f 100644 --- a/packages/js/product-editor/src/blocks/product-fields/inventory-email/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/inventory-email/block.json @@ -1,11 +1,16 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-inventory-email-field", "title": "Stock level threshold", "category": "widgets", "description": "Stock management minimum quantity.", - "keywords": [ "products", "inventory", "email", "minimum" ], + "keywords": [ + "products", + "inventory", + "email", + "minimum" + ], "textdomain": "default", "attributes": { "name": { @@ -23,4 +28,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/inventory-quantity/block.json b/packages/js/product-editor/src/blocks/product-fields/inventory-quantity/block.json index fe649ca6a38..67b23f5d447 100644 --- a/packages/js/product-editor/src/blocks/product-fields/inventory-quantity/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/inventory-quantity/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-inventory-quantity-field", "title": "Product inventory quantity available", "category": "woocommerce", "description": "The product available quantity.", - "keywords": [ "products", "quantity", "inventory" ], + "keywords": [ + "products", + "quantity", + "inventory" + ], "textdomain": "default", "attributes": { "name": { @@ -22,5 +26,7 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/inventory-sku/block.json b/packages/js/product-editor/src/blocks/product-fields/inventory-sku/block.json index 5608abb15a1..39940b25b6c 100644 --- a/packages/js/product-editor/src/blocks/product-fields/inventory-sku/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/inventory-sku/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-sku-field", "title": "Product text control", "category": "woocommerce", "description": "The product sku.", - "keywords": [ "products", "sku" ], + "keywords": [ + "products", + "sku" + ], "textdomain": "default", "attributes": { "name": { @@ -27,5 +30,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/name/block.json b/packages/js/product-editor/src/blocks/product-fields/name/block.json index 4196c26f22c..06f41489f8c 100644 --- a/packages/js/product-editor/src/blocks/product-fields/name/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/name/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-name-field", "title": "Product name", "category": "widgets", "description": "The product name.", - "keywords": [ "products", "name", "title" ], + "keywords": [ + "products", + "name", + "title" + ], "textdomain": "default", "attributes": { "name": { @@ -27,4 +31,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/notice-edit-single-variation/block.json b/packages/js/product-editor/src/blocks/product-fields/notice-edit-single-variation/block.json index bc9bc1b23cf..1704cb9762b 100644 --- a/packages/js/product-editor/src/blocks/product-fields/notice-edit-single-variation/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/notice-edit-single-variation/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-single-variation-notice", "title": "Notice", "category": "woocommerce", "description": "Notice description", - "keywords": [ "products", "notice" ], + "keywords": [ + "products", + "notice" + ], "textdomain": "default", "attributes": { "title": { @@ -31,4 +34,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/notice-has-variations/block.json b/packages/js/product-editor/src/blocks/product-fields/notice-has-variations/block.json index 5537dd68381..655557e52ed 100644 --- a/packages/js/product-editor/src/blocks/product-fields/notice-has-variations/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/notice-has-variations/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-has-variations-notice", "title": "Notice", "category": "woocommerce", "description": "Notice description", - "keywords": [ "products", "notice" ], + "keywords": [ + "products", + "notice" + ], "textdomain": "default", "attributes": { "title": { @@ -31,4 +34,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/password/block.json b/packages/js/product-editor/src/blocks/product-fields/password/block.json index 15f4517dc22..35044a5d4e8 100644 --- a/packages/js/product-editor/src/blocks/product-fields/password/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/password/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-password-field", "description": "A checkbox and an input to type a password to view a product.", "title": "Product password", "category": "widgets", - "keywords": [ "products", "password" ], + "keywords": [ + "products", + "password" + ], "textdomain": "default", "attributes": { "label": { @@ -23,4 +26,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/product-details-section-description/block.json b/packages/js/product-editor/src/blocks/product-fields/product-details-section-description/block.json index c3c390e70d4..8f43d17d52b 100644 --- a/packages/js/product-editor/src/blocks/product-fields/product-details-section-description/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/product-details-section-description/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-details-section-description", "title": "Product details section description", "category": "woocommerce", "description": "The product details section description.", - "keywords": [ "products", "section", "description" ], + "keywords": [ + "products", + "section", + "description" + ], "textdomain": "default", "attributes": { "content": { @@ -24,4 +28,4 @@ }, "usesContext": [ "selectedTab" ], "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/product-list/block.json b/packages/js/product-editor/src/blocks/product-fields/product-list/block.json index 644a6a4a18b..e32abe029ae 100644 --- a/packages/js/product-editor/src/blocks/product-fields/product-list/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/product-list/block.json @@ -1,11 +1,13 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-list-field", "title": "Product list", "category": "widgets", "description": "The product list.", - "keywords": [ "products" ], + "keywords": [ + "products" + ], "textdomain": "default", "attributes": { "property": { @@ -23,5 +25,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/regular-price/block.json b/packages/js/product-editor/src/blocks/product-fields/regular-price/block.json index ae8a00100d8..50ac2bd40a7 100644 --- a/packages/js/product-editor/src/blocks/product-fields/regular-price/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/regular-price/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-regular-price-field", "description": "A product price block with currency display.", "title": "Product regular price", "category": "widgets", - "keywords": [ "products", "price" ], + "keywords": [ + "products", + "price" + ], "textdomain": "default", "attributes": { "label": { @@ -36,6 +39,8 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType" ], + "usesContext": [ + "postType" + ], "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/sale-price/block.json b/packages/js/product-editor/src/blocks/product-fields/sale-price/block.json index b68ecb4522a..0854aca955d 100644 --- a/packages/js/product-editor/src/blocks/product-fields/sale-price/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/sale-price/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-sale-price-field", "description": "A product price block with currency display.", "title": "Product sale price", "category": "widgets", - "keywords": [ "products", "price" ], + "keywords": [ + "products", + "price" + ], "textdomain": "default", "attributes": { "label": { @@ -32,6 +35,8 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType" ], + "usesContext": [ + "postType" + ], "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/schedule-sale/block.json b/packages/js/product-editor/src/blocks/product-fields/schedule-sale/block.json index fe4a0d8dc6f..147ef02fb3d 100644 --- a/packages/js/product-editor/src/blocks/product-fields/schedule-sale/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/schedule-sale/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-schedule-sale-fields", "title": "Product schedule sale fields", "category": "woocommerce", "description": "The product schedule sale fields.", - "keywords": [ "products", "schedule", "sale" ], + "keywords": [ + "products", + "schedule", + "sale" + ], "textdomain": "default", "attributes": { "name": { @@ -23,5 +27,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/shipping-class/block.json b/packages/js/product-editor/src/blocks/product-fields/shipping-class/block.json index 3ff8fcaccd5..bc52ab051bb 100644 --- a/packages/js/product-editor/src/blocks/product-fields/shipping-class/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/shipping-class/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-shipping-class-field", "title": "Product shipping class field", "category": "woocommerce", "description": "The product shipping class field.", - "keywords": [ "products", "shipping", "class" ], + "keywords": [ + "products", + "shipping", + "class" + ], "textdomain": "default", "attributes": { "title": { @@ -26,5 +30,8 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType", "isInSelectedTab" ] -} + "usesContext": [ + "postType", + "isInSelectedTab" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/shipping-dimensions/block.json b/packages/js/product-editor/src/blocks/product-fields/shipping-dimensions/block.json index d012cf18546..abe8db37d3d 100644 --- a/packages/js/product-editor/src/blocks/product-fields/shipping-dimensions/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/shipping-dimensions/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-shipping-dimensions-fields", "title": "Product shipping dimensions fields", "category": "woocommerce", "description": "The product shipping dimensions fields.", - "keywords": [ "products", "shipping", "dimensions" ], + "keywords": [ + "products", + "shipping", + "dimensions" + ], "textdomain": "default", "attributes": { "__contentEditable": { @@ -27,5 +31,7 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/summary/block.json b/packages/js/product-editor/src/blocks/product-fields/summary/block.json index 50a10675278..fec3164c06a 100644 --- a/packages/js/product-editor/src/blocks/product-fields/summary/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/summary/block.json @@ -1,11 +1,15 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-summary-field", "title": "Product summary", "category": "widgets", "description": "The product summary.", - "keywords": [ "products", "summary", "excerpt" ], + "keywords": [ + "products", + "summary", + "excerpt" + ], "textdomain": "default", "attributes": { "property": { @@ -31,7 +35,10 @@ }, "direction": { "type": "string", - "enum": [ "ltr", "rtl" ] + "enum": [ + "ltr", + "rtl" + ] }, "label": { "type": "string" @@ -53,5 +60,7 @@ "lock": false }, "editorStyle": "file:./editor.css", - "usesContext": [ "postType" ] -} + "usesContext": [ + "postType" + ] +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/tag/block.json b/packages/js/product-editor/src/blocks/product-fields/tag/block.json index 57c997a6bd1..8e5724eb69b 100644 --- a/packages/js/product-editor/src/blocks/product-fields/tag/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/tag/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-tag-field", "title": "Product Tag", "category": "widgets", "description": "A field to select product tags.", - "keywords": [ "products", "tag" ], + "keywords": [ + "products", + "tag" + ], "textdomain": "default", "attributes": { "name": { @@ -19,7 +22,10 @@ "type": "string" } }, - "usesContext": [ "postType", "isInSelectedTab" ], + "usesContext": [ + "postType", + "isInSelectedTab" + ], "supports": { "align": false, "html": false, @@ -30,4 +36,4 @@ "__experimentalToolbar": false }, "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/variation-items/block.json b/packages/js/product-editor/src/blocks/product-fields/variation-items/block.json index 7c0ad11950c..1dc1d746e62 100644 --- a/packages/js/product-editor/src/blocks/product-fields/variation-items/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/variation-items/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-variation-items-field", "title": "Product variations items", "category": "woocommerce", "description": "The product variations items.", - "keywords": [ "products", "variations" ], + "keywords": [ + "products", + "variations" + ], "textdomain": "default", "attributes": { "description": { @@ -22,6 +25,8 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "isInSelectedTab" ], + "usesContext": [ + "isInSelectedTab" + ], "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/packages/js/product-editor/src/blocks/product-fields/variation-options/block.json b/packages/js/product-editor/src/blocks/product-fields/variation-options/block.json index 4b2f7c70d33..e16d5ebb37f 100644 --- a/packages/js/product-editor/src/blocks/product-fields/variation-options/block.json +++ b/packages/js/product-editor/src/blocks/product-fields/variation-options/block.json @@ -1,11 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-variations-options-field", "title": "Product variations options", "category": "woocommerce", "description": "The product variations options.", - "keywords": [ "products", "variations" ], + "keywords": [ + "products", + "variations" + ], "textdomain": "default", "attributes": { "description": { @@ -22,6 +25,9 @@ "lock": false, "__experimentalToolbar": false }, - "usesContext": [ "postType", "isInSelectedTab" ], + "usesContext": [ + "postType", + "isInSelectedTab" + ], "editorStyle": "file:./editor.css" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/add-to-cart-form/block.json b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/add-to-cart-form/block.json index 7eff52de309..f25ab844939 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/add-to-cart-form/block.json +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/add-to-cart-form/block.json @@ -10,9 +10,13 @@ "default": false } }, - "keywords": [ "WooCommerce" ], - "usesContext": [ "postId" ], + "keywords": [ + "WooCommerce" + ], + "usesContext": [ + "postId" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/block.json b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/block.json index a3785daacac..db05491ea58 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/block.json +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/block.json @@ -1,17 +1,20 @@ { "name": "woocommerce/product-average-rating", - "version": "1.0.0", "title": "Product Average Rating (Beta)", "description": "Display the average rating of a product", + "apiVersion": 3, "category": "woocommerce-product-elements", "attributes": { "textAlign": { "type": "string" } }, - "keywords": [ "WooCommerce" ], - "ancestor": [ "woocommerce/single-product" ], + "keywords": [ + "WooCommerce" + ], + "ancestor": [ + "woocommerce/single-product" + ], "textdomain": "woocommerce", - "apiVersion": 2, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/index.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/index.tsx index 6933405fd81..c3e836d0958 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/average-rating/index.tsx @@ -12,6 +12,7 @@ import edit from './edit'; import { supports } from './support'; registerBlockType( metadata, { + apiVersion: 3, icon: { src: ( = { /> ), }, + apiVersion: 3, supports: { html: false, }, diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx index b2fb5190c17..2b631c74dcd 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx @@ -19,7 +19,6 @@ import { const blockConfig: BlockConfiguration = { ...sharedConfig, - apiVersion: 2, title, description, icon: { src: icon }, diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/stock-indicator/index.ts b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/stock-indicator/index.ts index 25f3c7b80b0..447a47a255f 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/stock-indicator/index.ts +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/stock-indicator/index.ts @@ -20,7 +20,6 @@ import { const blockConfig: BlockConfiguration = { ...sharedConfig, - apiVersion: 2, title, description, icon: { src: icon }, diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/summary/index.ts b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/summary/index.ts index bbeec6f903e..3be1618d733 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/summary/index.ts +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/summary/index.ts @@ -23,7 +23,6 @@ const blockConfig: BlockConfiguration = { // Product Summary is not expected to be available in Product Collection, // Products (Beta) or Single Product blocks. They use core/post-summary variation. ancestor: [ 'woocommerce/all-products' ], - apiVersion: 2, title, description, icon: { src: icon }, diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/title/index.ts b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/title/index.ts index 5cfeb7cb072..cb1c1eaa890 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/title/index.ts +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/title/index.ts @@ -24,7 +24,6 @@ const blockConfig: BlockConfiguration = { // Product Title is not expected to be available in Product Collection // nor Products (Beta). They use core/post-title variation. ancestor: [ 'woocommerce/all-products', 'woocommerce/single-product' ], - apiVersion: 2, title, description, icon: { src: icon }, diff --git a/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.json b/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.json index 9ba7d97fe16..b7b1acb2d6d 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/active-filters/block.json @@ -4,7 +4,9 @@ "title": "Active Filters Controls", "description": "Display the currently active filters.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "html": false, "multiple": false, @@ -26,6 +28,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/active-filters/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/active-filters/index.tsx index abedf4dc3cb..51d9549ba71 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/active-filters/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/active-filters/index.tsx @@ -17,6 +17,7 @@ import { Attributes } from './types'; import deprecated from './deprecated'; registerBlockType( metadata, { + apiVersion: 3, icon: { src: ( ), category: 'woocommerce', - apiVersion: 2, + apiVersion: 3, keywords: [ __( 'WooCommerce', 'woocommerce' ) ], description: template && TEMPLATES[ template ] diff --git a/plugins/woocommerce-blocks/assets/js/blocks/coming-soon/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/coming-soon/index.tsx index afcb33008ad..592f0a96581 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/coming-soon/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/coming-soon/index.tsx @@ -18,6 +18,6 @@ registerBlockType( metadata, { title: __( 'Coming Soon', 'woocommerce' ), edit: Edit, save: Save, - apiVersion: 2, + apiVersion: 3, deprecated, } ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/customer-account/block.json b/plugins/woocommerce-blocks/assets/js/blocks/customer-account/block.json index 512803b8096..a33a0892763 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/customer-account/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/customer-account/block.json @@ -4,7 +4,10 @@ "title": "Customer account", "description": "A block that allows your customers to log in and out of their accounts in your store.", "category": "woocommerce", - "keywords": [ "WooCommerce", "My Account" ], + "keywords": [ + "WooCommerce", + "My Account" + ], "supports": { "align": true, "color": { @@ -34,6 +37,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-category/block.json b/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-category/block.json index eb53e95c6e5..44ad7c7211d 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-category/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-category/block.json @@ -103,6 +103,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-product/block.json b/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-product/block.json index 55c08b285f4..a5bf6fa86ce 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-product/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/featured-items/featured-product/block.json @@ -4,9 +4,14 @@ "title": "Featured Product", "description": "Highlight a product or variation.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "color": { "background": true, @@ -103,6 +108,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/filter-wrapper/block.json b/plugins/woocommerce-blocks/assets/js/blocks/filter-wrapper/block.json index 10cfda10e0a..0de45fd1c92 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/filter-wrapper/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/filter-wrapper/block.json @@ -3,7 +3,9 @@ "version": "1.0.0", "title": "Filter Block", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "attributes": { "filterType": { "type": "string" @@ -13,6 +15,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/handpicked-products/block.json b/plugins/woocommerce-blocks/assets/js/blocks/handpicked-products/block.json index 2536b42c5df..bafcf137fbc 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/handpicked-products/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/handpicked-products/block.json @@ -2,10 +2,16 @@ "name": "woocommerce/handpicked-products", "title": "Hand-picked Products", "category": "woocommerce", - "keywords": [ "Handpicked Products", "WooCommerce" ], + "keywords": [ + "Handpicked Products", + "WooCommerce" + ], "description": "Display a selection of hand-picked products in a grid.", "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false }, "attributes": { @@ -75,6 +81,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.json index 20ce152ea89..73513f950ad 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/block.json @@ -5,7 +5,9 @@ "icon": "miniCartAlt", "description": "Display a button for shoppers to quickly view their cart.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "textdomain": "woocommerce", "supports": { "html": false, @@ -64,6 +66,6 @@ "default": "greater_than_zero" } }, - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/index.tsx index e3aeeb4fb6a..187f931be20 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/index.tsx @@ -15,7 +15,7 @@ import { blockName, attributes } from './attributes'; import './inner-blocks'; const settings: BlockConfiguration = { - apiVersion: 2, + apiVersion: 3, title: __( 'Mini-Cart Contents', 'woocommerce' ), icon: { src: ( diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json index 9af0bac96b3..cd49ea901eb 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/empty-mini-cart-contents-block/block.json @@ -21,8 +21,10 @@ } } }, - "parent": [ "woocommerce/mini-cart-contents" ], + "parent": [ + "woocommerce/mini-cart-contents" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json index df3609f9f3f..e25a755e523 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/filled-mini-cart-contents-block/block.json @@ -21,8 +21,10 @@ } } }, - "parent": [ "woocommerce/mini-cart-contents" ], + "parent": [ + "woocommerce/mini-cart-contents" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-cart-button-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-cart-button-block/block.json index 415baba9b2f..cf2ae0da1b7 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-cart-button-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-cart-button-block/block.json @@ -35,8 +35,10 @@ "isDefault": true } ], - "parent": [ "woocommerce/mini-cart-footer-block" ], + "parent": [ + "woocommerce/mini-cart-footer-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-checkout-button-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-checkout-button-block/block.json index f87c29701d5..9bd81fcefd2 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-checkout-button-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-checkout-button-block/block.json @@ -39,6 +39,6 @@ "woocommerce/mini-cart-footer-block" ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-footer-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-footer-block/block.json index bbfe0f24d44..49a829da1ed 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-footer-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-footer-block/block.json @@ -21,8 +21,10 @@ } } }, - "parent": [ "woocommerce/filled-mini-cart-contents-block" ], + "parent": [ + "woocommerce/filled-mini-cart-contents-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-items-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-items-block/block.json index 69abe6f4447..f21eb47995f 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-items-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-items-block/block.json @@ -21,8 +21,10 @@ } } }, - "parent": [ "woocommerce/filled-mini-cart-contents-block" ], + "parent": [ + "woocommerce/filled-mini-cart-contents-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-products-table-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-products-table-block/block.json index 46c91406ef9..ceeaf1188cc 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-products-table-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-products-table-block/block.json @@ -21,8 +21,10 @@ } } }, - "parent": [ "woocommerce/mini-cart-items-block" ], + "parent": [ + "woocommerce/mini-cart-items-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json index bc98141b19e..d9d21e44e7a 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-shopping-button-block/block.json @@ -35,8 +35,10 @@ "label": "Outline" } ], - "parent": [ "woocommerce/empty-mini-cart-contents-block" ], + "parent": [ + "woocommerce/empty-mini-cart-contents-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-block/block.json index b42857a9166..bdb2c30799d 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-block/block.json @@ -28,8 +28,10 @@ } } }, - "parent": [ "woocommerce/filled-mini-cart-contents-block" ], + "parent": [ + "woocommerce/filled-mini-cart-contents-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-items-counter-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-items-counter-block/block.json index 1e54422052c..a3052821c37 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-items-counter-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-items-counter-block/block.json @@ -22,8 +22,10 @@ "padding": true } }, - "parent": [ "woocommerce/mini-cart-title-block" ], + "parent": [ + "woocommerce/mini-cart-title-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-label-block/block.json b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-label-block/block.json index 1aded1f66f0..c93e4b23885 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-label-block/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/mini-cart-title-label-block/block.json @@ -27,8 +27,10 @@ "type": "string" } }, - "parent": [ "woocommerce/mini-cart-title-block" ], + "parent": [ + "woocommerce/mini-cart-title-block" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields-wrapper/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields-wrapper/block.json index d02b803e6fd..c15329131c9 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields-wrapper/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields-wrapper/block.json @@ -29,6 +29,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" } \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields/block.json index 86303f32e56..7a75f32b25a 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-fields/block.json @@ -4,10 +4,15 @@ "title": "Additional Field List", "description": "Display the list of additional field values from the current order.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "__experimentalBorder": { "color": true, @@ -39,6 +44,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-information/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-information/block.json index ed6f4ee1036..ede9cdfa24a 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-information/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/additional-information/block.json @@ -4,10 +4,15 @@ "title": "Additional Information", "description": "Displays additional information provided by third-party extensions for the current order.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "__experimentalBorder": { "color": true, @@ -39,6 +44,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-address/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-address/block.json index 99d6b221588..977e876841d 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-address/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-address/block.json @@ -4,10 +4,15 @@ "title": "Billing Address", "description": "Display the order confirmation billing address.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "inserter": false, "html": false, "color": { @@ -57,6 +62,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-wrapper/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-wrapper/block.json index c6290a0533b..7bd022c3558 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-wrapper/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/billing-wrapper/block.json @@ -4,7 +4,9 @@ "title": "Billing Address Section", "description": "Display the order confirmation billing section.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "attributes": { "heading": { "type": "string" @@ -12,7 +14,10 @@ }, "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "spacing": { "padding": true, @@ -24,6 +29,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads-wrapper/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads-wrapper/block.json index c1b97b0d724..9d08219e127 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads-wrapper/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads-wrapper/block.json @@ -4,7 +4,9 @@ "title": "Downloads Section", "description": "Display the downloadable products section.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "attributes": { "heading": { "type": "string" @@ -12,7 +14,10 @@ }, "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "spacing": { "padding": true, @@ -24,6 +29,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads/block.json index 032e7f73938..c621c278fb5 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/downloads/block.json @@ -4,10 +4,15 @@ "title": "Order Downloads", "description": "Display links to purchased downloads.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "typography": { "fontSize": true, @@ -63,6 +68,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-address/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-address/block.json index 498498adf06..db0ede781a9 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-address/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-address/block.json @@ -4,10 +4,15 @@ "title": "Shipping Address", "description": "Display the order confirmation shipping address.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "inserter": false, "html": false, "color": { @@ -57,6 +62,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-wrapper/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-wrapper/block.json index 17e4518729d..7d67e1587d0 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-wrapper/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/shipping-wrapper/block.json @@ -4,7 +4,9 @@ "title": "Shipping Address Section", "description": "Display the order confirmation shipping section.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "attributes": { "heading": { "type": "string", @@ -13,7 +15,10 @@ }, "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "spacing": { "padding": true, @@ -25,6 +30,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/status/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/status/block.json index 3b958019a5c..f8225091d30 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/status/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/status/block.json @@ -4,10 +4,15 @@ "title": "Order Status", "description": "Display a \"thank you\" message, or a sentence regarding the current order status.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "typography": { "fontSize": true, @@ -51,6 +56,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/summary/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/summary/block.json index 77f05893b9c..6ef42e4b122 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/summary/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/summary/block.json @@ -4,10 +4,15 @@ "title": "Order Summary", "description": "Display the order summary on the order confirmation page.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "typography": { "fontSize": true, @@ -60,6 +65,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals-wrapper/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals-wrapper/block.json index 037b4b7bb71..1a6691f8775 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals-wrapper/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals-wrapper/block.json @@ -4,7 +4,9 @@ "title": "Order Totals Section", "description": "Display the order details section.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "attributes": { "heading": { "type": "string" @@ -12,7 +14,10 @@ }, "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "spacing": { "padding": true, @@ -24,6 +29,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals/block.json b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals/block.json index 29af4a4e636..066c4387db7 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/order-confirmation/totals/block.json @@ -4,10 +4,15 @@ "title": "Order Totals", "description": "Display the items purchased and order totals.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "multiple": false, - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "typography": { "fontSize": true, @@ -63,6 +68,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/page-content-wrapper/block.json b/plugins/woocommerce-blocks/assets/js/blocks/page-content-wrapper/block.json index b64cf0003be..e5bea02edbb 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/page-content-wrapper/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/page-content-wrapper/block.json @@ -4,7 +4,9 @@ "title": "WooCommerce Page", "description": "Displays WooCommerce page content.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "textdomain": "woocommerce", "supports": { "html": false, @@ -21,6 +23,6 @@ "postId": "postId", "postType": "postType" }, - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.json index 59735786503..17812e5c961 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.json @@ -4,7 +4,9 @@ "title": "Filter by Price Controls", "description": "Enable customers to filter the product grid by choosing a price range.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "html": false, "multiple": false, @@ -38,6 +40,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-best-sellers/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-best-sellers/block.json index a649b63ab05..d1a6ab3d79e 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-best-sellers/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-best-sellers/block.json @@ -2,10 +2,15 @@ "name": "woocommerce/product-best-sellers", "title": "Best Selling Products", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "description": "Display a grid of your all-time best selling products.", "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false }, "attributes": { @@ -87,6 +92,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.json index f30532e84d9..b2084211469 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.json @@ -3,9 +3,14 @@ "title": "Product Categories List", "category": "woocommerce", "description": "Show all product categories as a list or dropdown.", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false, "color": { "background": false, @@ -40,10 +45,10 @@ "type": "boolean", "default": true }, - "showChildrenOnly": { - "type": "boolean", - "default": false - } + "showChildrenOnly": { + "type": "boolean", + "default": false + } }, "example": { "attributes": { @@ -52,6 +57,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-category/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-category/block.json index 99d07e66e81..36c6af38b90 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-category/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-category/block.json @@ -2,10 +2,15 @@ "name": "woocommerce/product-category", "title": "Products by Category", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "description": "Display a grid of products from your selected categories.", "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false }, "attributes": { @@ -87,6 +92,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/block.json index 631cf7ce3a5..d45ee539ab9 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/block.json @@ -1,12 +1,16 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-collection", "version": "1.0.0", "title": "Product Collection", "description": "Display a collection of products from your store.", "category": "woocommerce", - "keywords": [ "WooCommerce", "Products (Beta)", "products" ], + "keywords": [ + "WooCommerce", + "Products (Beta)", + "products" + ], "textdomain": "woocommerce", "attributes": { "queryId": { @@ -53,10 +57,13 @@ }, "usesContext": [ "templateSlug", "postId" ], "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "anchor": true, "html": false, "__experimentalLayout": true, "interactivity": true } -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/block.json index 3cf41cf54aa..bd07a4b1563 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/block.json @@ -4,15 +4,23 @@ "title": "Product Filter (Experimental)", "description": "A block that adds product filters to the product collection.", "category": "woocommerce", - "keywords": [ "WooCommerce", "Filters" ], + "keywords": [ + "WooCommerce", + "Filters" + ], "textdomain": "woocommerce", "supports": { "html": false, "reusable": false, "inserter": false }, - "ancestor": [ "woocommerce/product-filters" ], - "usesContext": [ "query", "queryId" ], + "ancestor": [ + "woocommerce/product-filters" + ], + "usesContext": [ + "query", + "queryId" + ], "attributes": { "filterType": { "type": "string" @@ -36,4 +44,4 @@ }, "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/block.json index 045349fe65e..6d002248202 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/block.json @@ -5,10 +5,14 @@ "title": "Filter Options", "description": "Display the currently active filters.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "textdomain": "woocommerce", - "apiVersion": 2, - "ancestor": [ "woocommerce/product-filter" ], + "apiVersion": 3, + "ancestor": [ + "woocommerce/product-filter" + ], "supports": { "interactivity": true, "inserter": false, @@ -17,11 +21,13 @@ "background": false } }, - "usesContext": [ "queryId" ], + "usesContext": [ + "queryId" + ], "attributes": { "displayStyle": { "type": "string", "default": "list" } } -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/block.json index 6a497c20a33..2cc947376f2 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/block.json @@ -5,10 +5,14 @@ "title": "Filter Options", "description": "Enable customers to filter the product grid by selecting one or more attributes, such as color.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "textdomain": "woocommerce", - "apiVersion": 2, - "ancestor": [ "woocommerce/product-filter" ], + "apiVersion": 3, + "ancestor": [ + "woocommerce/product-filter" + ], "supports": { "interactivity": true, "inserter": false, @@ -55,7 +59,10 @@ } } }, - "usesContext": [ "query", "queryId" ], + "usesContext": [ + "query", + "queryId" + ], "attributes": { "attributeId": { "type": "number", @@ -94,4 +101,4 @@ "default":true } } -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/block.json index afbd38c530e..091659a2495 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/block.json @@ -5,12 +5,17 @@ "title": "Clear (Experimental)", "description": "Allows shoppers to reset this filter.", "category": "woocommerce", - "keywords": [ "WooCommerce", "reset filter" ], + "keywords": [ + "WooCommerce", + "reset filter" + ], "textdomain": "woocommerce", - "apiVersion": 2, - "ancestor": [ "woocommerce/product-filter" ], + "apiVersion": 3, + "ancestor": [ + "woocommerce/product-filter" + ], "supports": { "interactivity": true, "inserter": false } -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/block.json index da2b28598c8..326a9c45ada 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/block.json @@ -5,15 +5,22 @@ "title": "Filter Options", "description": "Enable customers to filter the product collection by choosing a price range.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "textdomain": "woocommerce", - "apiVersion": 2, - "ancestor": [ "woocommerce/product-filter" ], + "apiVersion": 3, + "ancestor": [ + "woocommerce/product-filter" + ], "supports": { "interactivity": true, "inserter": false }, - "usesContext": [ "query", "queryId" ], + "usesContext": [ + "query", + "queryId" + ], "attributes": { "showInputFields": { "type": "boolean", @@ -24,4 +31,4 @@ "default": false } } -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/block.json index a1f35fb4845..813f26f495a 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/block.json @@ -4,7 +4,9 @@ "title": "Filter Options", "description": "Enable customers to filter the product collection by rating.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "interactivity": true, "inserter": false, @@ -13,8 +15,13 @@ "text": true } }, - "ancestor": [ "woocommerce/product-filter" ], - "usesContext": [ "query", "queryId" ], + "ancestor": [ + "woocommerce/product-filter" + ], + "usesContext": [ + "query", + "queryId" + ], "attributes": { "className": { "type": "string", @@ -38,6 +45,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/block.json index 384b0186e14..1b023dccbbe 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/block.json @@ -4,7 +4,11 @@ "title": "Filter Options", "description": "Enable customers to filter the product collection by stock status.", "category": "woocommerce", - "keywords": [ "WooCommerce", "filter", "stock" ], + "keywords": [ + "WooCommerce", + "filter", + "stock" + ], "supports": { "interactivity": true, "html": false, @@ -37,9 +41,14 @@ "default": false } }, - "usesContext": [ "query", "queryId" ], - "ancestor": [ "woocommerce/product-filter" ], + "usesContext": [ + "query", + "queryId" + ], + "ancestor": [ + "woocommerce/product-filter" + ], "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/block.json index a2241e3d294..6278e472b09 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/block.json @@ -1,12 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-filters-overlay", "version": "1.0.0", "title": "Product Filters Overlay (Experimental)", "description": "Display product filters in an overlay on top of a page.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "align": true, "multiple": false, @@ -48,4 +50,4 @@ } }, "example": {} -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/block.json index ead6774c95c..ec5bd9b5d3c 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filters/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/block.json @@ -1,12 +1,14 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-filters", "version": "1.0.0", "title": "Product Filters (Experimental)", "description": "Let shoppers filter products displayed on the page.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "align": true, "__experimentalBorder": { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/block.json index 7480b7784a2..ed40700ddd7 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/block.json @@ -1,19 +1,23 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "woocommerce/product-gallery", "version": "1.0.0", "title": "Product Gallery (Beta)", "description": "Showcase your products relevant images and media.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "supports": { "align": true, "multiple": false, "interactivity": true }, "textdomain": "woocommerce", - "usesContext": [ "postId" ], + "usesContext": [ + "postId" + ], "providesContext": { "thumbnailsPosition": "thumbnailsPosition", "thumbnailsNumberOfThumbnails": "thumbnailsNumberOfThumbnails", @@ -54,7 +58,7 @@ "type": "boolean", "default": true }, - "nextPreviousButtonsPosition":{ + "nextPreviousButtonsPosition": { "type": "string", "default": "insideTheImage" }, @@ -65,4 +69,4 @@ }, "viewScript": "wc-product-gallery-frontend", "example": {} -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image-next-previous/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image-next-previous/block.json index 911c3f31f6d..fc9841a74d8 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image-next-previous/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image-next-previous/block.json @@ -1,14 +1,20 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "woocommerce/product-gallery-large-image-next-previous", - "version": "1.0.0", - "title": "Next/Previous Buttons", - "description": "Display next and previous buttons.", - "category": "woocommerce", - "keywords": [ "WooCommerce" ], - "usesContext": [ "nextPreviousButtonsPosition", "productGalleryClientId", "postId"], - "textdomain": "woocommerce", + "apiVersion": 3, + "name": "woocommerce/product-gallery-large-image-next-previous", + "version": "1.0.0", + "title": "Next/Previous Buttons", + "description": "Display next and previous buttons.", + "category": "woocommerce", + "keywords": [ + "WooCommerce" + ], + "usesContext": [ + "nextPreviousButtonsPosition", + "productGalleryClientId", + "postId" + ], + "textdomain": "woocommerce", "supports": { "layout": { "default": { @@ -21,5 +27,7 @@ "allowInheriting": false } }, - "ancestor": [ "woocommerce/product-gallery-large-image" ] -} + "ancestor": [ + "woocommerce/product-gallery-large-image" + ] +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image/block.json index 56e5870d316..aba37b694a2 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-large-image/block.json @@ -1,16 +1,26 @@ { - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, "name": "woocommerce/product-gallery-large-image", "version": "1.0.0", "title": "Large Image", "description": "Display the Large Image of a product.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], - "usesContext": [ "nextPreviousButtonsPosition", "postId", "hoverZoom", "fullScreenOnClick", "cropImages"], - "supports": { - "interactivity": true - }, + "keywords": [ + "WooCommerce" + ], + "usesContext": [ + "nextPreviousButtonsPosition", + "postId", + "hoverZoom", + "fullScreenOnClick", + "cropImages" + ], + "supports": { + "interactivity": true + }, "textdomain": "woocommerce", - "ancestor": [ "woocommerce/product-gallery" ] -} + "ancestor": [ + "woocommerce/product-gallery" + ] +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-pager/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-pager/block.json index b08b3c9294a..80d2ff36620 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-pager/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-pager/block.json @@ -1,13 +1,22 @@ { - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, "name": "woocommerce/product-gallery-pager", "version": "1.0.0", "title": "Pager", "description": "Display the gallery pager.", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "textdomain": "woocommerce", - "ancestor": [ "woocommerce/product-gallery" ], - "usesContext": [ "pagerDisplayMode", "productGalleryClientId", "thumbnailsNumberOfThumbnails", "postId" ] -} + "ancestor": [ + "woocommerce/product-gallery" + ], + "usesContext": [ + "pagerDisplayMode", + "productGalleryClientId", + "thumbnailsNumberOfThumbnails", + "postId" + ] +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-thumbnails/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-thumbnails/block.json index 60f470aaef2..a23592c9b03 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-thumbnails/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-gallery/inner-blocks/product-gallery-thumbnails/block.json @@ -1,15 +1,26 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "woocommerce/product-gallery-thumbnails", - "version": "1.0.0", - "title": "Thumbnails", - "description": "Display the Thumbnails of a product.", - "category": "woocommerce", - "keywords": [ "WooCommerce" ], - "usesContext": [ "postId", "thumbnailsPosition", "thumbnailsNumberOfThumbnails", "productGalleryClientId", "mode", "cropImages" ], - "textdomain": "woocommerce", - "ancestor": [ "woocommerce/product-gallery" ], + "apiVersion": 3, + "name": "woocommerce/product-gallery-thumbnails", + "version": "1.0.0", + "title": "Thumbnails", + "description": "Display the Thumbnails of a product.", + "category": "woocommerce", + "keywords": [ + "WooCommerce" + ], + "usesContext": [ + "postId", + "thumbnailsPosition", + "thumbnailsNumberOfThumbnails", + "productGalleryClientId", + "mode", + "cropImages" + ], + "textdomain": "woocommerce", + "ancestor": [ + "woocommerce/product-gallery" + ], "supports": { "spacing": { "margin": true, @@ -18,4 +29,4 @@ } } } -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-new/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-new/block.json index fcb471f9d67..d0c71441363 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-new/block.json +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-new/block.json @@ -2,10 +2,15 @@ "name": "woocommerce/product-new", "title": "Newest Products", "category": "woocommerce", - "keywords": [ "WooCommerce" ], + "keywords": [ + "WooCommerce" + ], "description": "Display a grid of your newest products.", "supports": { - "align": [ "wide", "full" ], + "align": [ + "wide", + "full" + ], "html": false }, "attributes": { @@ -87,6 +92,6 @@ } }, "textdomain": "woocommerce", - "apiVersion": 2, + "apiVersion": 3, "$schema": "https://schemas.wp.org/trunk/block.json" -} +} \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/block.tsx index a4735d50890..8f1ee05cc51 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/block.tsx @@ -6,6 +6,7 @@ import { Disabled, Placeholder } from '@wordpress/components'; import ServerSideRender from '@wordpress/server-side-render'; import { gridBlockPreview } from '@woocommerce/resource-previews'; import { Icon, percent } from '@wordpress/icons'; +import { useBlockProps } from '@wordpress/block-editor'; /** * Internal dependencies @@ -39,13 +40,14 @@ const ProductOnSaleBlock: React.FunctionComponent< Props > = ( props: Props ) => { const { attributes, setAttributes, name } = props; + const blockProps = useBlockProps(); if ( attributes.isPreview ) { - return gridBlockPreview; + return
{ gridBlockPreview }
; } return ( - <> +
= ( EmptyResponsePlaceholder={ EmptyPlaceholder } /> - +
); }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/index.js b/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/index.js index f93f70c3f13..d567b00c06a 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/index.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-on-sale/index.js @@ -15,6 +15,7 @@ import sharedAttributes, { registerBlockType( 'woocommerce/product-on-sale', { title: __( 'On Sale Products', 'woocommerce' ), + apiVersion: 3, icon: { src: ( { registerBlockType( 'woocommerce/product-search', { title: __( 'Product Search', 'woocommerce' ), + apiVersion: 3, icon: { src: ( { test( 'block can be inserted and it sorts reviews by most recent by default', async ( { frontendUtils, - page, editor, } ) => { - await expect( page.getByText( allReviews[ 0 ].review ) ).toBeVisible(); + await expect( + editor.canvas.getByText( allReviews[ 0 ].review ) + ).toBeVisible(); await editor.publishAndVisitPost(); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/attributes-filter/attribute-filter.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/attributes-filter/attribute-filter.block_theme.spec.ts index 203aa6f0890..7466fd0bbf6 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/attributes-filter/attribute-filter.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/attributes-filter/attribute-filter.block_theme.spec.ts @@ -40,15 +40,17 @@ test.describe( `${ blockData.name } Block`, () => { await editor.openDocumentSettingsSidebar(); } ); - test( "should allow changing the block's title", async ( { page } ) => { + test( "should allow changing the block's title", async ( { editor } ) => { const textSelector = '.wp-block-woocommerce-filter-wrapper .wp-block-heading'; const title = 'New Title'; - await page.locator( textSelector ).fill( title ); + await editor.canvas.locator( textSelector ).fill( title ); - await expect( page.locator( textSelector ) ).toHaveText( title ); + await expect( editor.canvas.locator( textSelector ) ).toHaveText( + title + ); } ); test( 'should allow changing the display style', async ( { @@ -59,7 +61,7 @@ test.describe( `${ blockData.name } Block`, () => { await editor.selectBlocks( attributeFilter ); await expect( - page.getByRole( 'checkbox', { name: 'Small' } ) + editor.canvas.getByRole( 'checkbox', { name: 'Small' } ) ).toBeVisible(); await page.getByLabel( 'DropDown' ).click(); @@ -71,10 +73,10 @@ test.describe( `${ blockData.name } Block`, () => { ).toBeHidden(); await expect( - page.getByRole( 'checkbox', { name: 'Small' } ) + editor.canvas.getByRole( 'checkbox', { name: 'Small' } ) ).toBeHidden(); - await expect( page.getByRole( 'combobox' ) ).toBeVisible(); + await expect( editor.canvas.getByRole( 'combobox' ) ).toBeVisible(); } ); test( 'should allow toggling the visibility of the filter button', async ( { diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/basic.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/basic.block_theme.spec.ts index c99e5903da2..3a96fd42bf9 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/basic.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/basic.block_theme.spec.ts @@ -13,6 +13,11 @@ test.describe( 'Basic role-based functionality tests', () => { page.getByRole( 'heading', { name: 'Dashboard' } ) ).toHaveText( 'Dashboard' ); } ); + + test( 'Load iframed post editor', async ( { admin, editor } ) => { + await admin.createNewPost(); + await expect( editor.canvas.owner() ).toBeVisible(); + } ); } ); test.describe( 'As customer', () => { diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/featured-category/featured-category.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/featured-category/featured-category.block_theme.spec.ts index 48c2273b742..c73c6b4c56c 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/featured-category/featured-category.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/featured-category/featured-category.block_theme.spec.ts @@ -56,11 +56,11 @@ test.describe( `${ blockData.slug } Block`, () => { const blockLocator = await editor.getBlockByName( blockData.slug ); await blockLocator.getByText( 'Test Category' ).click(); await blockLocator.getByText( 'Done' ).click(); - await editor.page.getByLabel( 'Edit category image' ).click(); - await editor.page.getByLabel( 'Rotate' ).click(); + await editor.clickBlockToolbarButton( 'Edit category image' ); + await editor.clickBlockToolbarButton( 'Rotate' ); await editor.page.getByRole( 'button', { name: 'Apply' } ).click(); await expect( - editor.page.locator( 'img[alt="Test Category"][src*="-edited"]' ) + editor.canvas.locator( 'img[alt="Test Category"][src*="-edited"]' ) ).toBeVisible(); } ); } ); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/featured-product/featured-product.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/featured-product/featured-product.block_theme.spec.ts index 54056ab2485..91f7ff6a0c3 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/featured-product/featured-product.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/featured-product/featured-product.block_theme.spec.ts @@ -35,11 +35,11 @@ test.describe( `${ blockData.slug } Block`, () => { const blockLocator = await editor.getBlockByName( blockData.slug ); await blockLocator.getByText( 'Album' ).click(); await blockLocator.getByText( 'Done' ).click(); - await editor.page.getByLabel( 'Edit product image' ).click(); - await editor.page.getByLabel( 'Rotate' ).click(); + await editor.clickBlockToolbarButton( 'Edit product image' ); + await editor.clickBlockToolbarButton( 'Rotate' ); await editor.page.getByRole( 'button', { name: 'Apply' } ).click(); await expect( - editor.page.locator( 'img[alt="Album"][src*="-edited"]' ) + editor.canvas.locator( 'img[alt="Album"][src*="-edited"]' ) ).toBeVisible(); } ); } ); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/page-content-wrapper/page-content-wrapper.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/page-content-wrapper/page-content-wrapper.block_theme.spec.ts index 2e298354992..fa39502fe26 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/page-content-wrapper/page-content-wrapper.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/page-content-wrapper/page-content-wrapper.block_theme.spec.ts @@ -54,7 +54,7 @@ for ( const template of templates ) { // Prevent trying to insert the paragraph block before the editor is // ready. await expect( - page.locator( template.blockClassName ) + editor.canvas.locator( template.blockClassName ) ).toBeVisible(); await editor.insertBlock( { diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/price-filter/price-filter.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/price-filter/price-filter.block_theme.spec.ts index 644aa5a08e1..da37e7b59c1 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/price-filter/price-filter.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/price-filter/price-filter.block_theme.spec.ts @@ -44,15 +44,17 @@ test.describe( `${ blockData.name } Block - editor side`, () => { await editor.openDocumentSettingsSidebar(); } ); - test( "should allow changing the block's title", async ( { page } ) => { + test( "should allow changing the block's title", async ( { editor } ) => { const textSelector = '.wp-block-woocommerce-filter-wrapper .wp-block-heading'; const title = 'New Title'; - await page.locator( textSelector ).fill( title ); + await editor.canvas.locator( textSelector ).fill( title ); - await expect( page.locator( textSelector ) ).toHaveText( title ); + await expect( editor.canvas.locator( textSelector ) ).toHaveText( + title + ); } ); test( 'should allow changing the display style', async ( { diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts index f1f0f2575dc..dd48320f303 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts @@ -59,21 +59,23 @@ test.describe( 'Product Collection', () => { } ); await expect( - page.getByLabel( 'Block: Products (Beta)' ) + editor.canvas.getByLabel( 'Block: Products (Beta)' ) ).toBeVisible(); - await page.getByRole( 'button', { name: 'Start blank' } ).click(); - await page.getByLabel( 'Title & Date' ).click(); + await editor.canvas + .getByRole( 'button', { name: 'Start blank' } ) + .click(); + await editor.canvas.getByLabel( 'Title & Date' ).click(); await page .getByRole( 'button', { name: 'Upgrade to Product Collection' } ) .click(); await expect( - page.getByLabel( 'Block: Products (Beta)' ) + editor.canvas.getByLabel( 'Block: Products (Beta)' ) ).toBeHidden(); await expect( - page.getByLabel( 'Block: Product Collection' ).first() + editor.canvas.getByLabel( 'Block: Product Collection' ).first() ).toBeVisible(); await expect( page.getByRole( 'button', { name: 'Choose collection' } ) @@ -93,11 +95,11 @@ test.describe( 'Product Collection', () => { 'Add to cart', // woocommerce/product-button ]; - test( 'In a post', async ( { page, pageObject } ) => { + test( 'In a post', async ( { page, editor, pageObject } ) => { await pageObject.createNewPostAndInsertBlock(); await expect( - page.locator( '[data-testid="product-image"]:visible' ) + editor.canvas.locator( '[data-testid="product-image"]:visible' ) ).toHaveCount( 9 ); await pageObject.insertProductElements(); @@ -216,8 +218,8 @@ test.describe( 'Product Collection', () => { } ) => { await pageObject.createNewPostAndInsertBlock(); - const allProducts = pageObject.products; - const saleProducts = pageObject.products.filter( { + let allProducts = pageObject.products; + let saleProducts = pageObject.products.filter( { hasText: 'Product on sale', } ); @@ -232,6 +234,11 @@ test.describe( 'Product Collection', () => { await expect( saleProducts ).toHaveCount( 6 ); await pageObject.publishAndGoToFrontend(); + await pageObject.refreshLocators( 'frontend' ); + allProducts = pageObject.products; + saleProducts = pageObject.products.filter( { + hasText: 'Product on sale', + } ); await expect( allProducts ).toHaveCount( 6 ); await expect( saleProducts ).toHaveCount( 6 ); @@ -758,6 +765,7 @@ test.describe( 'Product Collection', () => { const postId = await editor.publishPost(); await page.goto( `/?p=${ postId }` ); + await pageObject.refreshLocators( 'frontend' ); await expect( pageObject.products ).toHaveCount( 2 ); @@ -1107,7 +1115,6 @@ test.describe( 'Product Collection', () => { } ); test( 'With multiple Pagination blocks', async ( { - page, admin, editor, pageObject, @@ -1115,7 +1122,9 @@ test.describe( 'Product Collection', () => { await admin.createNewPost(); await pageObject.insertProductCollection(); await pageObject.chooseCollectionInPost( 'productCatalog' ); - const paginations = page.getByLabel( BLOCK_LABELS.pagination ); + const paginations = editor.canvas.getByLabel( + BLOCK_LABELS.pagination + ); await expect( paginations ).toHaveCount( 1 ); @@ -1409,15 +1418,12 @@ test.describe( 'Product Collection', () => { editor, } ) => { await pageObject.createNewPostAndInsertBlock(); - const productTemplate = page.getByLabel( - BLOCK_LABELS.productTemplate - ); - await expect( productTemplate ).toBeVisible(); + await expect( pageObject.productTemplate ).toBeVisible(); // Refresh the post and verify the block is still visible await editor.publishPost(); await page.reload(); - await expect( productTemplate ).toBeVisible(); + await expect( pageObject.productTemplate ).toBeVisible(); } ); test( 'On Sale collection should be visible after Refresh', async ( { @@ -1449,15 +1455,12 @@ test.describe( 'Product Collection', () => { editor, } ) => { await pageObject.createNewPostAndInsertBlock( 'onSale' ); - const productTemplate = page.getByLabel( - BLOCK_LABELS.productTemplate - ); - await expect( productTemplate ).toBeVisible(); + await expect( pageObject.productTemplate ).toBeVisible(); // Refresh the post and verify "On Sale" collection is still visible await editor.saveDraft(); await page.reload(); - await expect( productTemplate ).toBeVisible(); + await expect( pageObject.productTemplate ).toBeVisible(); } ); } ); @@ -1726,18 +1729,17 @@ test.describe( 'Testing registerProductCollection', () => { pageObject, editor, admin, - page, } ) => { await admin.createNewPost(); await editor.insertBlockUsingGlobalInserter( pageObject.BLOCK_NAME ); - await page + await editor.canvas .getByRole( 'button', { name: 'Choose collection', } ) .click(); // Get text of all buttons in the collection chooser - const collectionChooserButtonsTexts = await editor.page + const collectionChooserButtonsTexts = await editor.canvas .locator( '.wc-blocks-product-collection__collection-button-title' ) .allTextContents(); @@ -1846,7 +1848,7 @@ test.describe( 'Testing registerProductCollection', () => { await pageObject.createNewPostAndInsertBlock( 'myCustomCollectionWithPreview' ); - const previewButtonLocator = editor.page.getByTestId( + const previewButtonLocator = editor.canvas.getByTestId( SELECTORS.previewButtonTestID ); @@ -1906,7 +1908,7 @@ test.describe( 'Testing registerProductCollection', () => { await pageObject.createNewPostAndInsertBlock( 'myCustomCollectionWithAdvancedPreview' ); - const previewButtonLocator = editor.page.getByTestId( + const previewButtonLocator = editor.canvas.getByTestId( SELECTORS.previewButtonTestID ); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts index e3958814926..22a0fb3e3e1 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts @@ -134,7 +134,7 @@ class ProductCollectionPage { ? collectionToButtonNameMap[ collection ] : collectionToButtonNameMap.productCatalog; - const placeholderSelector = this.admin.page.locator( + const placeholderSelector = this.editor.canvas.locator( SELECTORS.collectionPlaceholder ); @@ -408,7 +408,7 @@ class ProductCollectionPage { name: 'Order by', } ); await orderByComboBox.selectOption( orderBy ); - await this.page.locator( SELECTORS.product ).first().waitFor(); + await this.editor.canvas.locator( SELECTORS.product ).first().waitFor(); await this.refreshLocators( 'editor' ); } @@ -743,11 +743,13 @@ class ProductCollectionPage { } private async initializeLocatorsForEditor() { - this.productTemplate = this.page.locator( SELECTORS.productTemplate ); - this.products = this.page + this.productTemplate = this.editor.canvas.locator( + SELECTORS.productTemplate + ); + this.products = this.editor.canvas .locator( SELECTORS.product ) .locator( 'visible=true' ); - this.productImages = this.page + this.productImages = this.editor.canvas .locator( SELECTORS.productImage.inEditor ) .locator( 'visible=true' ); this.productTitles = this.productTemplate @@ -756,10 +758,10 @@ class ProductCollectionPage { this.productPrices = this.productTemplate .locator( SELECTORS.productPrice.inEditor ) .locator( 'visible=true' ); - this.addToCartButtons = this.page + this.addToCartButtons = this.editor.canvas .locator( SELECTORS.addToCartButton.inEditor ) .locator( 'visible=true' ); - this.pagination = this.page.getByRole( 'document', { + this.pagination = this.editor.canvas.getByRole( 'document', { name: 'Block: Pagination', } ); } diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/rating-filter/rating-filter.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/rating-filter/rating-filter.block_theme.spec.ts index 0d7c4f9cd60..a92e204b61c 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/rating-filter/rating-filter.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/rating-filter/rating-filter.block_theme.spec.ts @@ -36,15 +36,17 @@ test.describe( `${ blockData.name } Block`, () => { await editor.openDocumentSettingsSidebar(); } ); - test( "should allow changing the block's title", async ( { page } ) => { + test( "should allow changing the block's title", async ( { editor } ) => { const textSelector = '.wp-block-woocommerce-filter-wrapper .wp-block-heading'; const title = 'New Title'; - await page.locator( textSelector ).fill( title ); + await editor.canvas.locator( textSelector ).fill( title ); - await expect( page.locator( textSelector ) ).toHaveText( title ); + await expect( editor.canvas.locator( textSelector ) ).toHaveText( + title + ); } ); test( 'should allow changing the display style', async ( { @@ -55,7 +57,7 @@ test.describe( `${ blockData.name } Block`, () => { await editor.selectBlocks( stockFilter ); await expect( - page.getByRole( 'checkbox', { name: 'Rated 1 out of 5' } ) + editor.canvas.getByRole( 'checkbox', { name: 'Rated 1 out of 5' } ) ).toBeVisible(); await page.getByLabel( 'DropDown' ).click(); @@ -67,10 +69,10 @@ test.describe( `${ blockData.name } Block`, () => { ).toBeHidden(); await expect( - page.getByRole( 'checkbox', { name: 'Rated 1 out of 5' } ) + editor.canvas.getByRole( 'checkbox', { name: 'Rated 1 out of 5' } ) ).toBeHidden(); - await expect( page.getByRole( 'combobox' ) ).toBeVisible(); + await expect( editor.canvas.getByRole( 'combobox' ) ).toBeVisible(); } ); test( 'should allow toggling the visibility of the filter button', async ( { diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-category/reviews-by-category.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-category/reviews-by-category.block_theme.spec.ts index 40e317d4694..57df6061853 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-category/reviews-by-category.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-category/reviews-by-category.block_theme.spec.ts @@ -30,14 +30,16 @@ test.describe( `${ BLOCK_NAME } Block`, () => { page, editor, } ) => { - const categoryCheckbox = page.getByLabel( 'Clothing' ); + const categoryCheckbox = editor.canvas.getByLabel( 'Clothing' ); await categoryCheckbox.check(); await expect( categoryCheckbox ).toBeChecked(); - const doneButton = page.getByRole( 'button', { name: 'Done' } ); + const doneButton = editor.canvas.getByRole( 'button', { + name: 'Done', + } ); await doneButton.click(); await expect( - page.getByText( hoodieReviews[ 0 ].review ) + editor.canvas.getByText( hoodieReviews[ 0 ].review ) ).toBeVisible(); await editor.publishAndVisitPost(); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-product/reviews-by-product.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-product/reviews-by-product.block_theme.spec.ts index 3f4c7d4165a..67875a09fc9 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-product/reviews-by-product.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/reviews-by-product/reviews-by-product.block_theme.spec.ts @@ -30,15 +30,19 @@ test.describe( `${ BLOCK_NAME } Block`, () => { page, editor, } ) => { - const productCheckbox = page.getByLabel( 'Hoodie, has 2 reviews' ); + const productCheckbox = editor.canvas.getByLabel( + 'Hoodie, has 2 reviews' + ); await productCheckbox.check(); await expect( productCheckbox ).toBeChecked(); - const doneButton = page.getByRole( 'button', { name: 'Done' } ); + const doneButton = editor.canvas.getByRole( 'button', { + name: 'Done', + } ); await doneButton.click(); await expect( - page.getByText( hoodieReviews[ 0 ].review ) + editor.canvas.getByText( hoodieReviews[ 0 ].review ) ).toBeVisible(); await editor.publishAndVisitPost(); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/stock-filter/stock-filter.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/stock-filter/stock-filter.block_theme.spec.ts index 765256309bf..bc00c4e846e 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/stock-filter/stock-filter.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/stock-filter/stock-filter.block_theme.spec.ts @@ -37,15 +37,17 @@ test.describe( `${ blockData.name } Block`, () => { await editor.openDocumentSettingsSidebar(); } ); - test( "should allow changing the block's title", async ( { page } ) => { + test( "should allow changing the block's title", async ( { editor } ) => { const textSelector = '.wp-block-woocommerce-filter-wrapper .wp-block-heading'; const title = 'New Title'; - await page.locator( textSelector ).fill( title ); + await editor.canvas.locator( textSelector ).fill( title ); - await expect( page.locator( textSelector ) ).toHaveText( title ); + await expect( editor.canvas.locator( textSelector ) ).toHaveText( + title + ); } ); test( 'should allow changing the display style', async ( { @@ -81,7 +83,7 @@ test.describe( `${ blockData.name } Block`, () => { } ) ).toBeHidden(); - await expect( page.getByRole( 'combobox' ) ).toBeVisible(); + await expect( editor.canvas.getByRole( 'combobox' ) ).toBeVisible(); } ); test( 'should allow toggling the visibility of the filter button', async ( { diff --git a/plugins/woocommerce/changelog/add-upgrade-blocks-to-v3 b/plugins/woocommerce/changelog/add-upgrade-blocks-to-v3 new file mode 100644 index 00000000000..def28ee9bcc --- /dev/null +++ b/plugins/woocommerce/changelog/add-upgrade-blocks-to-v3 @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Update all blocks to use API Version 3. diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/mini-cart.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/mini-cart.spec.js index 573510cac3d..502c1c2068a 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/mini-cart.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/mini-cart.spec.js @@ -2,6 +2,7 @@ const { test, expect } = require( '@playwright/test' ); const { disableWelcomeModal, openEditorSettings, + getCanvas, } = require( '../../utils/editor' ); const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default; const { random } = require( '../../utils/helpers' ); @@ -136,11 +137,13 @@ test.describe( await disableWelcomeModal( { page } ); + const canvas = await getCanvas( page ); + // add page title and mini cart block - await page + await canvas .getByRole( 'textbox', { name: 'Add title' } ) .fill( miniCartPageTitle ); - await page.getByLabel( 'Add block' ).click(); + await canvas.getByLabel( 'Add block' ).click(); await page .getByLabel( 'Search for blocks and patterns' ) .fill( '/mini cart' ); @@ -148,13 +151,15 @@ test.describe( .getByRole( 'option' ) .filter( { hasText: 'Mini-Cart' } ) .click(); - await expect( page.getByLabel( 'Block: Mini-Cart' ) ).toBeVisible(); + await expect( + canvas.getByLabel( 'Block: Mini-Cart' ) + ).toBeVisible(); // Open Settings sidebar if closed await openEditorSettings( { page } ); // customize mini cart block - await page.getByLabel( 'Block: Mini-Cart' ).click(); + await canvas.getByLabel( 'Block: Mini-Cart' ).click(); // display total price await page.getByLabel( 'Display total price' ).click(); // open drawer when a product diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/product-tags-attributes.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/product-tags-attributes.spec.js index acb5651b7af..5221f51f19c 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/product-tags-attributes.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/product-tags-attributes.spec.js @@ -1,7 +1,7 @@ const { test, expect, request } = require( '@playwright/test' ); const { admin } = require( '../../test-data/data' ); const pageTitle = 'Product Showcase'; -const { goToPageEditor } = require( '../../utils/editor' ); +const { goToPageEditor, getCanvas } = require( '../../utils/editor' ); const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default; const singleProductPrice1 = '5.00'; @@ -282,15 +282,17 @@ test.describe( // create as a merchant a new page with Product Collection block await goToPageEditor( { page } ); - await page + const canvas = await getCanvas( page ); + + await canvas .getByRole( 'textbox', { name: 'Add Title' } ) .fill( pageTitle ); - await page + await canvas .getByRole( 'button', { name: 'Add default block' } ) .click(); - await page + await canvas .getByRole( 'document', { name: 'Empty block; start writing or type forward slash to choose a block', } ) @@ -298,7 +300,7 @@ test.describe( await page.keyboard.press( 'Enter' ); // Product Collection requires choosing some collection. - await page + await canvas .locator( '[data-type="woocommerce/product-collection"] .components-placeholder' ) @@ -331,7 +333,7 @@ test.describe( await expect( page.getByRole( 'heading', { name: pageTitle } ) ).toBeVisible(); - await expect( + expect( await page .getByRole( 'button', { name: 'Add to cart' } ) .count() diff --git a/plugins/woocommerce/tests/e2e-pw/utils/editor.js b/plugins/woocommerce/tests/e2e-pw/utils/editor.js index 18c73af4714..7b2a17ea71c 100644 --- a/plugins/woocommerce/tests/e2e-pw/utils/editor.js +++ b/plugins/woocommerce/tests/e2e-pw/utils/editor.js @@ -104,7 +104,7 @@ const insertBlockByShortcut = async ( page, blockName ) => { ).toBeVisible(); await page.getByRole( 'option', { name: blockName, exact: true } ).click(); await expect( - page.getByLabel( `Block: ${ blockName }` ).first() + canvas.getByLabel( `Block: ${ blockName }` ).first() ).toBeVisible(); }; From 905fe2246f6a7c6144ddfab992c1e761123c910e Mon Sep 17 00:00:00 2001 From: RJ <27843274+rjchow@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:48:49 +0800 Subject: [PATCH 031/185] fix: reduce core profiler sticky footer height (#50788) * fix: reduce core profiler sticky footer height * increased height to 120px --- plugins/woocommerce-admin/client/core-profiler/style.scss | 6 +++--- .../fix-core-profiler-plugins-reduce-footer-height | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-core-profiler-plugins-reduce-footer-height diff --git a/plugins/woocommerce-admin/client/core-profiler/style.scss b/plugins/woocommerce-admin/client/core-profiler/style.scss index b7d3679a547..256e5671730 100644 --- a/plugins/woocommerce-admin/client/core-profiler/style.scss +++ b/plugins/woocommerce-admin/client/core-profiler/style.scss @@ -346,7 +346,7 @@ } } - $sticky-footer-height: 140px; + $sticky-footer-height: 120px; .woocommerce-profiler-plugins__list { display: flex; @@ -356,7 +356,7 @@ flex: 50%; @mixin sticky-footer-scroll-padding { - padding-bottom: $sticky-footer-height; + padding-bottom: $sticky-footer-height + 32px; } @include breakpoint(">782px") {// sticky footer shouldn't apply to mobile layout @@ -426,7 +426,7 @@ @mixin plugins-sticky-footer { background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #fff 44.69%); - height: 140px; + height: $sticky-footer-height; position: fixed; bottom: 0; } diff --git a/plugins/woocommerce/changelog/fix-core-profiler-plugins-reduce-footer-height b/plugins/woocommerce/changelog/fix-core-profiler-plugins-reduce-footer-height new file mode 100644 index 00000000000..c69dd8e21e3 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-core-profiler-plugins-reduce-footer-height @@ -0,0 +1,5 @@ +Significance: patch +Type: tweak + +Reduce core profiler sticky footer height + From 5098bb116908a5cd8ab61780ba50d2259482148b Mon Sep 17 00:00:00 2001 From: piinthecloud Date: Tue, 20 Aug 2024 13:19:47 +0200 Subject: [PATCH 032/185] create block theme folder (#50638) * create block theme folder * add changelog * update titles --- docs/block-theme-development/README.md | 5 ++ .../cart-and-checkout.md | 21 ++----- .../block-theme-development}/css-styling.md | 30 ++++------ .../theming-woo-blocks.md | 26 ++------ docs/docs-manifest.json | 59 +++++++++++++------ docs/theme-development/README.md | 6 +- plugins/woocommerce/changelog/move-theme-docs | 4 ++ 7 files changed, 77 insertions(+), 74 deletions(-) create mode 100644 docs/block-theme-development/README.md rename {plugins/woocommerce-blocks/docs/designers/theming => docs/block-theme-development}/cart-and-checkout.md (81%) rename {plugins/woocommerce-blocks/docs/designers/theming => docs/block-theme-development}/css-styling.md (69%) rename plugins/woocommerce-blocks/docs/designers/theming/README.md => docs/block-theme-development/theming-woo-blocks.md (91%) create mode 100644 plugins/woocommerce/changelog/move-theme-docs diff --git a/docs/block-theme-development/README.md b/docs/block-theme-development/README.md new file mode 100644 index 00000000000..7b2564c7433 --- /dev/null +++ b/docs/block-theme-development/README.md @@ -0,0 +1,5 @@ +--- +category_title: Block Theme Development +category_slug: block-theme-development +post_title: Block theme development +--- \ No newline at end of file diff --git a/plugins/woocommerce-blocks/docs/designers/theming/cart-and-checkout.md b/docs/block-theme-development/cart-and-checkout.md similarity index 81% rename from plugins/woocommerce-blocks/docs/designers/theming/cart-and-checkout.md rename to docs/block-theme-development/cart-and-checkout.md index 5af905846d8..f3151f8fa5c 100644 --- a/plugins/woocommerce-blocks/docs/designers/theming/cart-and-checkout.md +++ b/docs/block-theme-development/cart-and-checkout.md @@ -1,13 +1,12 @@ -# Cart and Checkout Blocks Theming +--- +post_title: Cart and checkout blocks theming +menu_title: Cart and Checkout Blocks Theming +tags: reference +--- > [!IMPORTANT] -> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be “private”, and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_. +> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be "private", and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_. -## Table of Contents - -- [Buttons](#buttons) -- [Mobile submit container](#mobile-submit-container) -- [Item quantity badge](#item-quantity-badge) ## Buttons @@ -81,13 +80,5 @@ By default, it uses a combination of black and white borders and shadows so it h ![Order summary screenshot with custom styles for the item quantity badge](https://user-images.githubusercontent.com/3616980/83863109-2e421c80-a723-11ea-9bf7-2033a96cf5b2.png) - ---- - -[We're hiring!](https://woocommerce.com/careers/) Come work with us! - -🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce-blocks/issues/new?assignees=&labels=type%3A+documentation&template=--doc-feedback.md&title=Feedback%20on%20./docs/designers/theming/cart-and-checkout.md) - - diff --git a/plugins/woocommerce-blocks/docs/designers/theming/css-styling.md b/docs/block-theme-development/css-styling.md similarity index 69% rename from plugins/woocommerce-blocks/docs/designers/theming/css-styling.md rename to docs/block-theme-development/css-styling.md index 978dfb7444d..2470d621ae0 100644 --- a/plugins/woocommerce-blocks/docs/designers/theming/css-styling.md +++ b/docs/block-theme-development/css-styling.md @@ -1,11 +1,15 @@ -# CSS Styling +--- +post_title: CSS styling for themes +menu_title: CSS Styling for Themes +tags: reference +--- ## Block and component class names > [!IMPORTANT] -> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be “private”, and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_. +> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be "private", and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_. -WooCommerce Blocks follows BEM for class names, as [stated in our coding guidelines](../../contributors/coding-guidelines.md). All classes start with one of these two prefixes: +WooCommerce Blocks follows BEM for class names, as [stated in our coding guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/contributors/coding-guidelines.md). All classes start with one of these two prefixes: * `.wc-block-`: class names specific to a single block. * `.wc-block-components-`: class names specific to a component. The component might be reused by different blocks. @@ -38,10 +42,10 @@ Those classes are: Container width | Class name ----------------|------------ -\>700px | `is-large` +\>700px | `is-large` 521px-700px | `is-medium` 401px-520px | `is-small` -<=400px | `is-mobile` +<=400px | `is-mobile` As an example, if we wanted to do the Checkout font size 10% larger when the container has a width of 521px or wider, we could do so with this code: @@ -54,9 +58,9 @@ As an example, if we wanted to do the Checkout font size 10% larger when the con ## WC Blocks _vs._ theme style conflicts for semantic elements -WooCommerce Blocks uses HTML elements according to their semantic meaning, not their default layout. That means that some times blocks might use an anchor link (``) but display it as a button. Or the other way around, a ` +
+ + +`; diff --git a/packages/js/components/src/analytics/error/tests/index.test.js b/packages/js/components/src/analytics/error/tests/index.test.js new file mode 100644 index 00000000000..d01f55c8724 --- /dev/null +++ b/packages/js/components/src/analytics/error/tests/index.test.js @@ -0,0 +1,62 @@ +/** + * External dependencies + */ +import { createElement } from '@wordpress/element'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +/** + * Internal dependencies + */ +import AnalyticsError from '..'; + +describe( 'AnalyticsError', () => { + // Mock window.location.reload by using a global variable + const originalLocation = window.location; + + beforeAll( () => { + delete window.location; + window.location = { reload: jest.fn() }; + } ); + + afterAll( () => { + window.location = originalLocation; + } ); + + it( 'displays an error message', () => { + render( ); + + expect( + screen.getByText( + 'There was an error getting your stats. Please try again.' + ) + ).toBeInTheDocument(); + } ); + + it( 'shows reload button', () => { + render( ); + + expect( + screen.getByRole( 'button', { name: 'Reload' } ) + ).toBeInTheDocument(); + } ); + + it( 'refreshes the page when Reload Page button is clicked', () => { + const reloadMock = jest.fn(); + Object.defineProperty( window.location, 'reload', { + configurable: true, + value: reloadMock, + } ); + + render( ); + + userEvent.click( screen.getByText( 'Reload' ) ); + + expect( reloadMock ).toHaveBeenCalled(); + } ); + + it( 'should match snapshot', () => { + const { container } = render( ); + expect( container ).toMatchSnapshot(); + } ); +} ); diff --git a/packages/js/components/src/analytics/index.js b/packages/js/components/src/analytics/index.js new file mode 100644 index 00000000000..ebf10a5b7e5 --- /dev/null +++ b/packages/js/components/src/analytics/index.js @@ -0,0 +1 @@ +export { default as AnalyticsError } from './error'; diff --git a/packages/js/components/src/index.ts b/packages/js/components/src/index.ts index ff64f547fda..06914504e6a 100644 --- a/packages/js/components/src/index.ts +++ b/packages/js/components/src/index.ts @@ -1,5 +1,6 @@ export { default as AbbreviatedCard } from './abbreviated-card'; export { default as AdvancedFilters } from './advanced-filters'; +export * from './analytics'; export { default as AnimationSlider } from './animation-slider'; export { default as Chart } from './chart'; export { default as ChartPlaceholder } from './chart/placeholder'; diff --git a/plugins/woocommerce-admin/client/analytics/components/index.js b/plugins/woocommerce-admin/client/analytics/components/index.js index cc02f168d36..4ee3476b0b2 100644 --- a/plugins/woocommerce-admin/client/analytics/components/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/index.js @@ -1,4 +1,3 @@ export { default as ReportChart } from './report-chart'; -export { default as ReportError } from './report-error'; export { default as ReportSummary } from './report-summary'; export { default as ReportTable } from './report-table'; diff --git a/plugins/woocommerce-admin/client/analytics/components/leaderboard/index.js b/plugins/woocommerce-admin/client/analytics/components/leaderboard/index.js index 98e9bdbd9b3..2e8d406247f 100644 --- a/plugins/woocommerce-admin/client/analytics/components/leaderboard/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/leaderboard/index.js @@ -5,7 +5,7 @@ import { __ } from '@wordpress/i18n'; import { Card, CardBody, CardHeader } from '@wordpress/components'; import { Component } from '@wordpress/element'; import { compose } from '@wordpress/compose'; -import { EmptyTable, TableCard } from '@woocommerce/components'; +import { EmptyTable, AnalyticsError, TableCard } from '@woocommerce/components'; import { withSelect } from '@wordpress/data'; import PropTypes from 'prop-types'; import { getPersistedQuery } from '@woocommerce/navigation'; @@ -21,7 +21,6 @@ import { Text } from '@woocommerce/experimental'; /** * Internal dependencies */ -import ReportError from '../report-error'; import sanitizeHTML from '../../../lib/sanitize-html'; import './style.scss'; @@ -88,7 +87,7 @@ export class Leaderboard extends Component { const classes = 'woocommerce-leaderboard'; if ( isError ) { - return ; + return ; } const rows = this.getFormattedRows(); diff --git a/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js b/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js index 31f714c3d91..a19830c0b44 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-chart/index.js @@ -8,7 +8,7 @@ import { format as formatDate } from '@wordpress/date'; import { withSelect } from '@wordpress/data'; import { get, isEqual } from 'lodash'; import PropTypes from 'prop-types'; -import { Chart } from '@woocommerce/components'; +import { Chart, AnalyticsError } from '@woocommerce/components'; import { getReportChartData, getTooltipValueFormat, @@ -27,7 +27,6 @@ import { CurrencyContext } from '@woocommerce/currency'; /** * Internal dependencies */ -import ReportError from '../report-error'; import { getChartMode, getSelectedFilter, @@ -197,7 +196,7 @@ export class ReportChart extends Component { const { isRequesting, primaryData } = this.props; if ( primaryData.isError ) { - return ; + return ; } const isChartRequesting = isRequesting || primaryData.isRequesting; @@ -214,7 +213,7 @@ export class ReportChart extends Component { const { isRequesting, primaryData, secondaryData } = this.props; if ( ! primaryData || primaryData.isError || secondaryData.isError ) { - return ; + return ; } const isChartRequesting = diff --git a/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js b/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js index 57eefcd17f2..ac1b509619b 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-summary/index.js @@ -8,6 +8,7 @@ import { withSelect } from '@wordpress/data'; import PropTypes from 'prop-types'; import { getNewPath } from '@woocommerce/navigation'; import { + AnalyticsError, SummaryList, SummaryListPlaceholder, SummaryNumber, @@ -21,7 +22,6 @@ import { CurrencyContext } from '@woocommerce/currency'; /** * Internal dependencies */ -import ReportError from '../report-error'; /** * Component to render summary numbers in reports. @@ -64,7 +64,7 @@ export class ReportSummary extends Component { const { isError, isRequesting } = summaryData; if ( isError ) { - return ; + return ; } if ( isRequesting ) { @@ -138,7 +138,7 @@ ReportSummary.propTypes = { * The endpoint to use in API calls to populate the Summary Numbers. * For example, if `taxes` is provided, data will be fetched from the report * `taxes` endpoint (ie: `/wc-analytics/reports/taxes/stats`). If the provided endpoint - * doesn't exist, an error will be shown to the user with `ReportError`. + * doesn't exist, an error will be shown to the user with `AnalyticsError`. */ endpoint: PropTypes.string.isRequired, /** diff --git a/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js b/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js index fa51e9abde8..970dee29eec 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js @@ -124,7 +124,7 @@ describe( 'ReportSummary', () => { expect( delta ).toBeInTheDocument(); } ); - test( 'should display ReportError when isError is true', () => { + test( 'should display AnalyticsError when isError is true', () => { renderChart( 'number', null, null, true ); expect( diff --git a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js index f43cf9f7996..6e049a9bacd 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js @@ -11,7 +11,12 @@ import { get, partial, uniq } from 'lodash'; import { __, sprintf } from '@wordpress/i18n'; import PropTypes from 'prop-types'; import { STORE_KEY as CES_STORE_KEY } from '@woocommerce/customer-effort-score'; -import { CompareButton, Search, TableCard } from '@woocommerce/components'; +import { + CompareButton, + AnalyticsError, + Search, + TableCard, +} from '@woocommerce/components'; import { getIdsFromQuery, getSearchWords, @@ -38,7 +43,6 @@ import { recordEvent } from '@woocommerce/tracks'; * Internal dependencies */ import DownloadIcon from './download-icon'; -import ReportError from '../report-error'; import { extendTableData } from './utils'; import './style.scss'; @@ -89,7 +93,7 @@ const ReportTable = ( props ) => { const isError = tableData.isError || primaryData.isError; if ( isError ) { - return ; + return ; } let userPrefColumns = []; @@ -489,7 +493,7 @@ ReportTable.propTypes = { * For example, if `taxes` is provided, data will be fetched from the report * `taxes` endpoint (ie: `/wc-analytics/reports/taxes` and `/wc/v4/reports/taxes/stats`). * If the provided endpoint doesn't exist, an error will be shown to the user - * with `ReportError`. + * with `AnalyticsError`. */ endpoint: PropTypes.string, /** diff --git a/plugins/woocommerce-admin/client/analytics/report/index.js b/plugins/woocommerce-admin/client/analytics/report/index.js index 85118becdbf..3a7da1d481d 100644 --- a/plugins/woocommerce-admin/client/analytics/report/index.js +++ b/plugins/woocommerce-admin/client/analytics/report/index.js @@ -8,6 +8,7 @@ import PropTypes from 'prop-types'; import { find } from 'lodash'; import { getQuery, getSearchWords } from '@woocommerce/navigation'; import { searchItemsByString, ITEMS_STORE_NAME } from '@woocommerce/data'; +import { AnalyticsError } from '@woocommerce/components'; import { CurrencyContext, getFilteredCurrencyInstance, @@ -18,7 +19,6 @@ import { */ import './style.scss'; import { NoMatch } from '~/layout/NoMatch'; -import ReportError from '../components/report-error'; import getReports from './get-reports'; /** @@ -83,7 +83,7 @@ class Report extends Component { const { isError } = this.props; if ( isError ) { - return ; + return ; } const reportParam = getReportParam( this.props ); diff --git a/plugins/woocommerce-admin/client/analytics/report/products/index.js b/plugins/woocommerce-admin/client/analytics/report/products/index.js index b3d7d893998..9307d67e207 100644 --- a/plugins/woocommerce-admin/client/analytics/report/products/index.js +++ b/plugins/woocommerce-admin/client/analytics/report/products/index.js @@ -6,6 +6,7 @@ import { Component, Fragment } from '@wordpress/element'; import { compose } from '@wordpress/compose'; import PropTypes from 'prop-types'; import { ITEMS_STORE_NAME } from '@woocommerce/data'; +import { AnalyticsError } from '@woocommerce/components'; import { withSelect } from '@wordpress/data'; /** @@ -15,7 +16,6 @@ import { advancedFilters, charts, filters } from './config'; import getSelectedChart from '../../../lib/get-selected-chart'; import ProductsReportTable from './table'; import ReportChart from '../../components/report-chart'; -import ReportError from '../../components/report-error'; import ReportSummary from '../../components/report-summary'; import VariationsReportTable from '../variations/table'; import ReportFilters from '../../components/report-filters'; @@ -57,7 +57,7 @@ class ProductsReport extends Component { this.props; if ( isError ) { - return ; + return ; } const chartQuery = { diff --git a/plugins/woocommerce-admin/client/analytics/report/variations/index.js b/plugins/woocommerce-admin/client/analytics/report/variations/index.js index cffd21f496b..17eb554577d 100644 --- a/plugins/woocommerce-admin/client/analytics/report/variations/index.js +++ b/plugins/woocommerce-admin/client/analytics/report/variations/index.js @@ -4,6 +4,7 @@ import { __ } from '@wordpress/i18n'; import { Fragment } from '@wordpress/element'; import PropTypes from 'prop-types'; +import { AnalyticsError } from '@woocommerce/components'; /** * Internal dependencies @@ -11,7 +12,6 @@ import PropTypes from 'prop-types'; import { advancedFilters, charts, filters } from './config'; import getSelectedChart from '../../../lib/get-selected-chart'; import ReportChart from '../../components/report-chart'; -import ReportError from '../../components/report-error'; import ReportSummary from '../../components/report-summary'; import VariationsReportTable from './table'; import ReportFilters from '../../components/report-filters'; @@ -35,7 +35,7 @@ const VariationsReport = ( props ) => { const { path, query, isError, isRequesting } = props; if ( isError ) { - return ; + return ; } const chartQuery = { diff --git a/plugins/woocommerce/changelog/36052-dev-move-report-error b/plugins/woocommerce/changelog/36052-dev-move-report-error new file mode 100644 index 00000000000..20189d203e2 --- /dev/null +++ b/plugins/woocommerce/changelog/36052-dev-move-report-error @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Move `ReportError` to `@woocommerce/components` as `AnalyticsError` From 94d3b2e05cc462fa17d783266a4a7aa03d4d3742 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:12:54 -0300 Subject: [PATCH 064/185] Update changelog.txt from release 9.2.1 (#50851) * Prep trunk post release 9.2.1 * Add 9.2.0's changelog --------- Co-authored-by: WooCommerce Bot Co-authored-by: Jorge Torres --- changelog.txt | 360 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 345 insertions(+), 15 deletions(-) diff --git a/changelog.txt b/changelog.txt index 01b8c0ed896..8d70dfca5bc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,336 @@ == Changelog == += 9.2.1 2024-08-21 = + +**WooCommerce** + +* Fix - Revert turning of AccessiblePrivateMethods::_accessible_private_methods into a static property because it caused fatal errors in some edge cases. [#50809](https://github.com/woocommerce/woocommerce/pull/50809) + += 9.2.0 2024-08-20 = + +**WooCommerce** + +* Update - Enhanced sanitization in `@woocommerce/currency`. [#50802](https://github.com/woocommerce/woocommerce/pull/50802) +* Fix - Hardening against XSS by leveraging HTML API for adding block attribute data. [#50801](https://github.com/woocommerce/woocommerce/pull/50801) +* Fix - Prevent downloads of digitial products after partial refund. [#50804](https://github.com/woocommerce/woocommerce/pull/50804) +* Add - Adds support for tracking downloads when a partial (ranged) request is made. [#50805](https://github.com/woocommerce/woocommerce/pull/50805) +* Update - Turn AccessiblePrivateMethods::_accessible_private_methods into a static property. [#50806](https://github.com/woocommerce/woocommerce/pull/50806) +* Fix - Correct label of shipping dimensions length field. [#50180](https://github.com/woocommerce/woocommerce/pull/50180) +* Fix - Allow new accounts to set new password even if logged in. [#50700](https://github.com/woocommerce/woocommerce/pull/50700) +* Fix - Remove global_unique_id from interface and add warning in case it is not implemented [#50685](https://github.com/woocommerce/woocommerce/pull/50685) +* Fix - CYS: avoid to enqueue Jetpack scripts [#50679](https://github.com/woocommerce/woocommerce/pull/50679) +* Fix - Clear product unique ID (`global_unique_id`) when duplicating products. [#50629](https://github.com/woocommerce/woocommerce/pull/50629) +* Fix - Resolved an issue that caused the page title and content text to display in the incorrect order on the Order Confirmation page. [#50592](https://github.com/woocommerce/woocommerce/pull/50592) +* Fix - Customer Account - Maintain the size of the icon in smaller screens. [#50410](https://github.com/woocommerce/woocommerce/pull/50410) +* Fix - Accessibility: Prevent shipping losing focus when making selections during checkout. [#48370](https://github.com/woocommerce/woocommerce/pull/48370) +* Fix - Add aria-label to mini-cart button on first render to improve accessibility [#48329](https://github.com/woocommerce/woocommerce/pull/48329) +* Fix - Add missing script dependencies to product variation generation script. [#49595](https://github.com/woocommerce/woocommerce/pull/49595) +* Fix - Address timing issue with React 18 when unregistering blocks and add missing dependency to editor bootstrapping code. [#49642](https://github.com/woocommerce/woocommerce/pull/49642) +* Fix - Add the "Customer account" block into the "Minimal Header" to fix the spacing. [#49893](https://github.com/woocommerce/woocommerce/pull/49893) +* Fix - Avoid Product Search Results block template to fall back to the Product Catalog template from the theme [#48887](https://github.com/woocommerce/woocommerce/pull/48887) +* Fix - Changed from using React.render to React.createRoot for product editor areas as it has been deprecated since React 18 [#48834](https://github.com/woocommerce/woocommerce/pull/48834) +* Fix - Check if parent product exists when creating attribute lookup data for variations [#49474](https://github.com/woocommerce/woocommerce/pull/49474) +* Fix - Check if there's an actual session available inside wc_clear_cart_after_payment [#45821](https://github.com/woocommerce/woocommerce/pull/45821) +* Fix - Comment: Update db_version variable and use it to prevent adding global_unique_id when the lookup table was not yet updated [#49472](https://github.com/woocommerce/woocommerce/pull/49472) +* Fix - Correctly escape the HTML when linking customer orders. [#49195](https://github.com/woocommerce/woocommerce/pull/49195) +* Fix - CSY - Fix intro banner copy for existing themes [#49787](https://github.com/woocommerce/woocommerce/pull/49787) +* Fix - CYS - Fix marking the CYS task as completed only by accessing the Intro page. [#49374](https://github.com/woocommerce/woocommerce/pull/49374) +* Fix - CYS - Remove the site title block length from the "Large Header" and the "Centered Menu Header". [#48671](https://github.com/woocommerce/woocommerce/pull/48671) +* Fix - CYS: Disable readonly mode only when full composability feature flag is enabled. [#48752](https://github.com/woocommerce/woocommerce/pull/48752) +* Fix - CYS: Ensure that the button in the Intro page redirects to the Customizer when a classic theme is enabled. [#49804](https://github.com/woocommerce/woocommerce/pull/49804) +* Fix - CYS: fix: Assembler follows admin color schema. [#49159](https://github.com/woocommerce/woocommerce/pull/49159) +* Fix - CYS: fix arrow welcome tour [#49607](https://github.com/woocommerce/woocommerce/pull/49607) +* Fix - CYS: Fix border width pattern preview. [#49753](https://github.com/woocommerce/woocommerce/pull/49753) +* Fix - CYS: Fix button background on Featured Category Cover image [#49659](https://github.com/woocommerce/woocommerce/pull/49659) +* Fix - CYS: fix drag to resize bar [#49657](https://github.com/woocommerce/woocommerce/pull/49657) +* Fix - CYS: fix flickering effect. [#48767](https://github.com/woocommerce/woocommerce/pull/48767) +* Fix - CYS: fix logic to disable click on the no block placeholder [#48722](https://github.com/woocommerce/woocommerce/pull/48722) +* Fix - CYS: Fix no block placeholder style. [#49673](https://github.com/woocommerce/woocommerce/pull/49673) +* Fix - CYS: Fix pattern rendering issues [#49041](https://github.com/woocommerce/woocommerce/pull/49041) +* Fix - CYS: fix pattern wrapped twice by group blocks [#48712](https://github.com/woocommerce/woocommerce/pull/48712) +* Fix - CYS: fix selected header/footer pattern [#49788](https://github.com/woocommerce/woocommerce/pull/49788) +* Fix - CYS: fix shuffle feature logic. [#49153](https://github.com/woocommerce/woocommerce/pull/49153) +* Fix - CYS: fix the default intro pattern. [#49082](https://github.com/woocommerce/woocommerce/pull/49082) +* Fix - CYS: Fix the tooltip overlap with the pattern. [#49700](https://github.com/woocommerce/woocommerce/pull/49700) +* Fix - CYS: fix toolbar position after the site preview resizes [#49028](https://github.com/woocommerce/woocommerce/pull/49028) +* Fix - CYS: hide button to resize the image [#48714](https://github.com/woocommerce/woocommerce/pull/48714) +* Fix - CYS: Hide shuffle button when only one pattern is available [#49790](https://github.com/woocommerce/woocommerce/pull/49790) +* Fix - CYS: not enable PTK features on WordPress 6.5. [#49591](https://github.com/woocommerce/woocommerce/pull/49591) +* Fix - CYS: open Intro panel when user clicks on Design your homepage [#49005](https://github.com/woocommerce/woocommerce/pull/49005) +* Fix - CYS: Remove not necessary placeholder on homepage sidebar. [#49705](https://github.com/woocommerce/woocommerce/pull/49705) +* Fix - CYS: show default TT4 fonts pair. [#49675](https://github.com/woocommerce/woocommerce/pull/49675) +* Fix - CYS: show logo when the header is updated. [#49681](https://github.com/woocommerce/woocommerce/pull/49681) +* Fix - Display "View store" button text by default in the toolbar. [#48690](https://github.com/woocommerce/woocommerce/pull/48690) +* Fix - Display admin notice of expired and expiring Woo subscription when the product + is connected / activated on the site. [#49717](https://github.com/woocommerce/woocommerce/pull/49717) +* Fix - Do not set the `tk_ai` tracking cookie if tracking is disabled. [#47863](https://github.com/woocommerce/woocommerce/pull/47863) +* Fix - Ensure the second address line input appears when using autofill [#49730](https://github.com/woocommerce/woocommerce/pull/49730) +* Fix - Ensure the Store API recalculates cart totals prior to running validation hooks. [#49455](https://github.com/woocommerce/woocommerce/pull/49455) +* Fix - Exclude simple products from variations reports by default. [#49244](https://github.com/woocommerce/woocommerce/pull/49244) +* Fix - Failure to fetch the country list no longer blocks users in the profiler. [#49519](https://github.com/woocommerce/woocommerce/pull/49519) +* Fix - Fetch site cache status correctly if directly navigating to LYS Success page, and some refactoring [#48710](https://github.com/woocommerce/woocommerce/pull/48710) +* Fix - Fix: Make woocommerce/product-price available in the Single Product template [#49906](https://github.com/woocommerce/woocommerce/pull/49906) +* Fix - Fix a bug where woocommerce removes the current-menu-item class. [#45095](https://github.com/woocommerce/woocommerce/pull/45095) +* Fix - Fix add product task to create template first and simplify logic [#49631](https://github.com/woocommerce/woocommerce/pull/49631) +* Fix - Fix add zone button flinching and vertical centering [#48869](https://github.com/woocommerce/woocommerce/pull/48869) +* Fix - Fix Analytics - Tax Report Pagination [#49562](https://github.com/woocommerce/woocommerce/pull/49562) +* Fix - Fix confusing messages prompting switch to classic templates [#48717](https://github.com/woocommerce/woocommerce/pull/48717) +* Fix - Fix default shipping selection when changing between pickup and shipping on block checkout. [#49718](https://github.com/woocommerce/woocommerce/pull/49718) +* Fix - Fixed "woocommerce_new_order" triggering on checkout blocks page visit. [#47422](https://github.com/woocommerce/woocommerce/pull/47422) +* Fix - Fixed a bug causing account email not to be taken in consideration for coupon validation when a customer has a different billing email set. [#48488](https://github.com/woocommerce/woocommerce/pull/48488) +* Fix - Fixed a bug that would cause incorrect pricing at checkout for very large amounts. [#49361](https://github.com/woocommerce/woocommerce/pull/49361) +* Fix - Fixed a bug where the close button is not visible on the mini cart when viewed on a mobile device [#48769](https://github.com/woocommerce/woocommerce/pull/48769) +* Fix - Fixed horizontal and vertical layout overflows on LYS success page [#49127](https://github.com/woocommerce/woocommerce/pull/49127) +* Fix - Fix fatal error in order reports when parent order doesn't exist [#49006](https://github.com/woocommerce/woocommerce/pull/49006) +* Fix - Fix get_options deprecated notice when viewing Analytics > Orders [#49092](https://github.com/woocommerce/woocommerce/pull/49092) +* Fix - Fix Order Count inconsistency between stats and reports [#49283](https://github.com/woocommerce/woocommerce/pull/49283) +* Fix - Fix sidebar attribute control in Products by Attribute block [#49351](https://github.com/woocommerce/woocommerce/pull/49351) +* Fix - Fix site coming soon page heading color [#49129](https://github.com/woocommerce/woocommerce/pull/49129) +* Fix - Fix Task List - Reminder bar close button styling [#49532](https://github.com/woocommerce/woocommerce/pull/49532) +* Fix - Fix the mini cart items not being visible when zoomed in [#48384](https://github.com/woocommerce/woocommerce/pull/48384) +* Fix - Fix the namespace of the RestApiControllerBase class [#49333](https://github.com/woocommerce/woocommerce/pull/49333) +* Fix - Fix the undefined array key "name" warning in ComingSoonRequestHandler.php when the font name is not set [#49795](https://github.com/woocommerce/woocommerce/pull/49795) +* Fix - Fix variation name in analytics variations report [#49440](https://github.com/woocommerce/woocommerce/pull/49440) +* Fix - Issue fixed where tags are overlapping divider line in "Filter by product category". [#48756](https://github.com/woocommerce/woocommerce/pull/48756) +* Fix - Made coupon fields during block checkout stack on smaller screen sizes [#48623](https://github.com/woocommerce/woocommerce/pull/48623) +* Fix - Make sure the correct block template file is used in the Site Editor for templates with fallback [#48621](https://github.com/woocommerce/woocommerce/pull/48621) +* Fix - Make the edit/delete actions of shipping/products in manual orders accessible [#48238](https://github.com/woocommerce/woocommerce/pull/48238) +* Fix - Make the Leaderboards on the Analytics > Dashboard page use consistent currency and number formatting across the page, and perceive the currency setting comes from the relevant filter. [#49097](https://github.com/woocommerce/woocommerce/pull/49097) +* Fix - Narrowed scope of block theme notice templates so other template overrides are unaffected [#48686](https://github.com/woocommerce/woocommerce/pull/48686) +* Fix - Prevent a warning showing when using the Shipping Address Calculator in combination with the additional checkout fields API [#49685](https://github.com/woocommerce/woocommerce/pull/49685) +* Fix - Prevent download permissions metabox from being toggled when toggling individual permission details. [#49022](https://github.com/woocommerce/woocommerce/pull/49022) +* Fix - Prevent possible type error in BatchProcessingController. [#49728](https://github.com/woocommerce/woocommerce/pull/49728) +* Fix - Prevent product editor styles loading on non wc-admin pages [#49170](https://github.com/woocommerce/woocommerce/pull/49170) +* Fix - Product Collection: allow custom collections to hide all of the filter controls, not only some of them [#49713](https://github.com/woocommerce/woocommerce/pull/49713) +* Fix - Product Collection: Fix alignment of the first item in Grid layout for WP 6.6 [#49096](https://github.com/woocommerce/woocommerce/pull/49096) +* Fix - Product Collection: Fix the Preview badge's corner radius [#48856](https://github.com/woocommerce/woocommerce/pull/48856) +* Fix - Product Collection: Show "Sync with current query" option only in archive templates where it makes sense [#48917](https://github.com/woocommerce/woocommerce/pull/48917) +* Fix - Product Fitlers: Bring back pattern [#49601](https://github.com/woocommerce/woocommerce/pull/49601) +* Fix - Product rating - Inherit the color of the star when no ratings [#49678](https://github.com/woocommerce/woocommerce/pull/49678) +* Fix - Provide more informative errors if a refund cannot be requested via the REST API, due to plugin conflicts. [#47918](https://github.com/woocommerce/woocommerce/pull/47918) +* Fix - Redirect the lost password page to edit account while logged in. [#49670](https://github.com/woocommerce/woocommerce/pull/49670) +* Fix - Removes several side effects in the code bases that caused translations to be loaded too early. [#47113](https://github.com/woocommerce/woocommerce/pull/47113) +* Fix - Remove strong tags from patterns [#49901](https://github.com/woocommerce/woocommerce/pull/49901) +* Fix - Replace the red CSS color with the $red SASS variable in WooCommerce legacy elements [#48742](https://github.com/woocommerce/woocommerce/pull/48742) +* Fix - Resolved issues with new order hook triggers during transitions to and from draft statuses. [#49098](https://github.com/woocommerce/woocommerce/pull/49098) +* Fix - Set coming soon preview body aspect ratio to 1/1 to fix broken template [#49749](https://github.com/woocommerce/woocommerce/pull/49749) +* Fix - Show variations only for the selected product's variations [#49470](https://github.com/woocommerce/woocommerce/pull/49470) +* Fix - Tooltips message is now selected based on the order status instead of the label of the order status, which would break if the current WordPress language was not English. Also passes the order object to the woocommerce_get_order_status_labels filter to allow for more personalized tooltips. [#49812](https://github.com/woocommerce/woocommerce/pull/49812) +* Fix - Update allowed statuses in legacy payment handler for checkout block. [#48788](https://github.com/woocommerce/woocommerce/pull/48788) +* Add - Use UTM parameters to link Tracks events from connect notice CTA and successful site connection [#50126](https://github.com/woocommerce/woocommerce/pull/50126) +* Add - Add a generic function to determine remote logging eligibility [#49371](https://github.com/woocommerce/woocommerce/pull/49371) +* Add - Add a rest api to manage the product custom fields [#48504](https://github.com/woocommerce/woocommerce/pull/48504) +* Add - Add column `global_unique_id` to `wc_product_meta_lookup` table + Add global_unique_id field to product and product variations [#49472](https://github.com/woocommerce/woocommerce/pull/49472) +* Add - Added notice to the order confirmation page for new accounts instructing them to change the default password. [#48673](https://github.com/woocommerce/woocommerce/pull/48673) +* Add - Add global unique ID field to the classic product editor [#49312](https://github.com/woocommerce/woocommerce/pull/49312) +* Add - Add placeholder options and validation to checkout country and state select inputs. [#49616](https://github.com/woocommerce/woocommerce/pull/49616) +* Add - Add Refresh Remote Inbox Notifications and Delete Remote Notification Tools [#48961](https://github.com/woocommerce/woocommerce/pull/48961) +* Add - Add some robots.txt rules about directories created by WooCommerce [#49432](https://github.com/woocommerce/woocommerce/pull/49432) +* Add - Adds product usage notice [#47697](https://github.com/woocommerce/woocommerce/pull/47697) +* Add - Add support to run e2e tests against WPCOM website. [#49403](https://github.com/woocommerce/woocommerce/pull/49403) +* Add - Add UTM parameters to missing payment method notice links. [#49621](https://github.com/woocommerce/woocommerce/pull/49621) +* Add - Add validation for `__experimentalRegisterProductCollection` arguments [#48141](https://github.com/woocommerce/woocommerce/pull/48141) +* Add - CYS: add badge that informs how many patterns have been inserted from each category. [#48668](https://github.com/woocommerce/woocommerce/pull/48668) +* Add - CYS: Add default patterns. [#48839](https://github.com/woocommerce/woocommerce/pull/48839) +* Add - CYS: Add Tracking for Fiverr Logo Maker CTA [#49783](https://github.com/woocommerce/woocommerce/pull/49783) +* Add - CYS: Enable the PTK feature. [#49565](https://github.com/woocommerce/woocommerce/pull/49565) +* Add - Expose __experimentalRegisterProductCollection in @woocommerce/blocks-registry Package [#48141](https://github.com/woocommerce/woocommerce/pull/48141) +* Add - Improvements in the handling of feature compatibility for plugins [#48169](https://github.com/woocommerce/woocommerce/pull/48169) +* Add - Product Collection: Rename "Sync with current query" option to "Use page context" and make it working in non-archive context as well [#49627](https://github.com/woocommerce/woocommerce/pull/49627) +* Update - Add pattern validation for global_unique_id [#50501](https://github.com/woocommerce/woocommerce/pull/50501) +* Update - Clear global_unique_id when restoring a product that doesn't have an unique id [#50496](https://github.com/woocommerce/woocommerce/pull/50496) +* Update - Use admin password reset on admin login screen [#50200](https://github.com/woocommerce/woocommerce/pull/50200) +* Update - Prevent creation of password-protected coupons. [#50236](https://github.com/woocommerce/woocommerce/pull/50236) +* Update - Add a link to the Theming docs from the blockified templates README.md file [#48538](https://github.com/woocommerce/woocommerce/pull/48538) +* Update - Add a new icon style to the "Customer Account" block. [#48979](https://github.com/woocommerce/woocommerce/pull/48979) +* Update - Adds setting to control the visibility of product count in Mini cart block [#48545](https://github.com/woocommerce/woocommerce/pull/48545) +* Update - Add tracking for enable auto renew links on notices [#49710](https://github.com/woocommerce/woocommerce/pull/49710) +* Update - Add UTM parameters to subscription renewal notice links. [#49645](https://github.com/woocommerce/woocommerce/pull/49645) +* Update - Adjust input field height and input label text size. [#49636](https://github.com/woocommerce/woocommerce/pull/49636) +* Update - Adjust top margin of the coupon code in the Cart and Checkout blocks. [#49603](https://github.com/woocommerce/woocommerce/pull/49603) +* Update - CYS - Add borders to footer and header patterns on the assembler. [#49299](https://github.com/woocommerce/woocommerce/pull/49299) +* Update - CYS - Add missing patterns to their categories for the assembler [#49154](https://github.com/woocommerce/woocommerce/pull/49154) +* Update - CYS - Add tracking events to pattern features. [#49556](https://github.com/woocommerce/woocommerce/pull/49556) +* Update - CYS - Disable the Full Composability for CYS AI flows [#49290](https://github.com/woocommerce/woocommerce/pull/49290) +* Update - CYS - Fetch patterns from the private dotcom patterns category instead of from the default source site. [#49007](https://github.com/woocommerce/woocommerce/pull/49007) +* Update - CYS - Fetch patterns from the WooCommerce PTK source site. [#48492](https://github.com/woocommerce/woocommerce/pull/48492) +* Update - CYS - Filter out patterns with external dependencies. [#48618](https://github.com/woocommerce/woocommerce/pull/48618) +* Update - CYS - Fix CSS spacing issues in the assembler. [#49232](https://github.com/woocommerce/woocommerce/pull/49232) +* Update - CYS - Fix dark patterns buttons color. [#49181](https://github.com/woocommerce/woocommerce/pull/49181) +* Update - CYS - Fix the column spacing for the "Four Image Grid Content Left" pattern [#49669](https://github.com/woocommerce/woocommerce/pull/49669) +* Update - CYS - Fix the font size of the "DON'T HAVE A LOGO YET?" title. [#49231](https://github.com/woocommerce/woocommerce/pull/49231) +* Update - CYS - Fix the intro cards size to match the designs. [#49297](https://github.com/woocommerce/woocommerce/pull/49297) +* Update - CYS - Fix the pattern preview border color on hover and for inserted patterns. [#49206](https://github.com/woocommerce/woocommerce/pull/49206) +* Update - CYS - Improve margins for CYS core patterns. [#49196](https://github.com/woocommerce/woocommerce/pull/49196) +* Update - CYS - Improve the designs of the Intro page bottom cards. [#48983](https://github.com/woocommerce/woocommerce/pull/48983) +* Update - CYS - Include the dotcom patterns from the "Reviews" category. [#49140](https://github.com/woocommerce/woocommerce/pull/49140) +* Update - CYS - Make some titles bold on CYS patterns. [#49151](https://github.com/woocommerce/woocommerce/pull/49151) +* Update - CYS - Make the patterns content translatable for patterns in the dictionary. [#49633](https://github.com/woocommerce/woocommerce/pull/49633) +* Update - CYS - Register PTK "Testimonials" patterns as "Reviews" [#48674](https://github.com/woocommerce/woocommerce/pull/48674) +* Update - CYS - Remove non-default patterns and register them from the PTK. Update margins. [#49101](https://github.com/woocommerce/woocommerce/pull/49101) +* Update - CYS - Schedule the `fetch_patterns` actions only once every hour. [#49754](https://github.com/woocommerce/woocommerce/pull/49754) +* Update - CYS - Update pattern categories and its descriptions. [#48665](https://github.com/woocommerce/woocommerce/pull/48665) +* Update - CYS - Update pattern toolbar delete button copy to `Delete`. [#49295](https://github.com/woocommerce/woocommerce/pull/49295) +* Update - CYS - Update the full composability layout styles [#49303](https://github.com/woocommerce/woocommerce/pull/49303) +* Update - CYS - Update the intro pages for different type of themes. [#49910](https://github.com/woocommerce/woocommerce/pull/49910) +* Update - CYS: Add the proper tracking string to the external Fiverr link in sidebar of the **Add your logo** screen. [#49745](https://github.com/woocommerce/woocommerce/pull/49745) +* Update - CYS: Add `rel="noreferrer"` to External Fiverr Link in sidebar of **Add your logo** screen. [#49314](https://github.com/woocommerce/woocommerce/pull/49314) +* Update - CYS: Improve Block Toolbar logic. [#48799](https://github.com/woocommerce/woocommerce/pull/48799) +* Update - CYS: improve copy no blocks placeholder. [#49030](https://github.com/woocommerce/woocommerce/pull/49030) +* Update - CYS: Improve patterns order [#49204](https://github.com/woocommerce/woocommerce/pull/49204) +* Update - CYS: no highlight the pattern when it is added. [#48802](https://github.com/woocommerce/woocommerce/pull/48802) +* Update - CYS: Remove margin last pattern preview [#49767](https://github.com/woocommerce/woocommerce/pull/49767) +* Update - CYS: Remove not necessary patterns. [#48750](https://github.com/woocommerce/woocommerce/pull/48750) +* Update - CYS: Revisit sidebar layout. [#48803](https://github.com/woocommerce/woocommerce/pull/48803) +* Update - CYS: Update Block Toolbar Position [#48662](https://github.com/woocommerce/woocommerce/pull/48662) +* Update - CYS: Update icon used by the "Customer account" block into header patterns [#49133](https://github.com/woocommerce/woocommerce/pull/49133) +* Update - CYS: Update sidebar homepage copy [#48882](https://github.com/woocommerce/woocommerce/pull/48882) +* Update - CYS: Update verbiage in the CTA to our Fiverr Logo Maker landing page. [#48987](https://github.com/woocommerce/woocommerce/pull/48987) +* Update - CYS: when the footer/header is clicked, the border color is blue. [#48765](https://github.com/woocommerce/woocommerce/pull/48765) +* Update - Deprecate and create new coming soon block version [#49786](https://github.com/woocommerce/woocommerce/pull/49786) +* Update - E2E: check the `Add` button when creating product variations in the new Product Editor [#48928](https://github.com/woocommerce/woocommerce/pull/48928) +* Update - E2E: in the new Product Editor app, update how to detect when global attributes are loaded. [#48915](https://github.com/woocommerce/woocommerce/pull/48915) +* Update - E2E: remove UI check when creating attribute global terms [#48934](https://github.com/woocommerce/woocommerce/pull/48934) +* Update - Ensure expiration-related modal is shown to the installed Woo subscriptions [#49747](https://github.com/woocommerce/woocommerce/pull/49747) +* Update - Ensures the product ID is valid when interacting with product variations via the REST API. [#48804](https://github.com/woocommerce/woocommerce/pull/48804) +* Update - Ensure that active plugins shown in the System Status api endpoint actually exist [#48709](https://github.com/woocommerce/woocommerce/pull/48709) +* Update - Ensuring product creation with unique sku for concurrent requests [#47476](https://github.com/woocommerce/woocommerce/pull/47476) +* Update - Fix: Show preview label only when Product Collection block is selected [#48795](https://github.com/woocommerce/woocommerce/pull/48795) +* Update - Fix Classic Template block registration on WP 6.6 [#48730](https://github.com/woocommerce/woocommerce/pull/48730) +* Update - Fix typo on Congratulations screen [#49233](https://github.com/woocommerce/woocommerce/pull/49233) +* Update - Hide account creation options not relevent to block checkout when using block checkout. [#49389](https://github.com/woocommerce/woocommerce/pull/49389) +* Update - Improve rendering of order list table on mobile. [#49592](https://github.com/woocommerce/woocommerce/pull/49592) +* Update - Improve the handling of the deprecated WC()->api property [#48884](https://github.com/woocommerce/woocommerce/pull/48884) +* Update - Make proceed to order button non sticky when zoom level is bigger than 100% [#48391](https://github.com/woocommerce/woocommerce/pull/48391) +* Update - Make Single Product gallery thumbnail images sharper by defining a srcset [#49112](https://github.com/woocommerce/woocommerce/pull/49112) +* Update - Migrate the cart and checkout block's state, country and custom field input to a native select [#48180](https://github.com/woocommerce/woocommerce/pull/48180) +* Update - Move remote logger to `./src` and improve `fetch_latest_woocommerce_version()` logic [#49639](https://github.com/woocommerce/woocommerce/pull/49639) +* Update - Optimize the method that gets the downloads count for a given download [#49008](https://github.com/woocommerce/woocommerce/pull/49008) +* Update - preparing checkout blocks docs for dev docs site [#49010](https://github.com/woocommerce/woocommerce/pull/49010) +* Update - Product Collection: revert renaming "Sync with current query" option [#49907](https://github.com/woocommerce/woocommerce/pull/49907) +* Update - Product Editor: improve E2E tests. Test the `+3 More` item label in the Organization tab [#48891](https://github.com/woocommerce/woocommerce/pull/48891) +* Update - Product Editor: restore and fix E2E test that creates product variations [#48725](https://github.com/woocommerce/woocommerce/pull/48725) +* Update - Product Editor: restore Product (local) Attributes E2E test [#48871](https://github.com/woocommerce/woocommerce/pull/48871) +* Update - Product Editor: update create product variations E2E test [#48627](https://github.com/woocommerce/woocommerce/pull/48627) +* Update - Redesigned the Product Collection block's insertion journey. [#48911](https://github.com/woocommerce/woocommerce/pull/48911) +* Update - Remove Jetpack copy experiment from core profiler [#49452](https://github.com/woocommerce/woocommerce/pull/49452) +* Update - Remove the hooked blocks feature gate and replace with wc_hooked_blocks_version option [#49302](https://github.com/woocommerce/woocommerce/pull/49302) +* Update - Replace the "Customer account" line logo. [#49666](https://github.com/woocommerce/woocommerce/pull/49666) +* Update - Return HTTP 404 for REST API requests involving non-existing tax class. [#48579](https://github.com/woocommerce/woocommerce/pull/48579) +* Update - Return HTTP 404 when accessing non-existent webhooks via REST API. [#48729](https://github.com/woocommerce/woocommerce/pull/48729) +* Update - Return HTTP 404 when trying to read or delete a non-existent product review. [#48726](https://github.com/woocommerce/woocommerce/pull/48726) +* Update - Run full e2e tests suite against Pressable and WPCOM websites. [#49597](https://github.com/woocommerce/woocommerce/pull/49597) +* Update - Update content for usage tracking modal for CYS experience [#49911](https://github.com/woocommerce/woocommerce/pull/49911) +* Update - Updated account settings descriptions for added clarity [#48556](https://github.com/woocommerce/woocommerce/pull/48556) +* Update - Update Jetpack's new SSO classes and methods to prevent deprecation notice. [#49752](https://github.com/woocommerce/woocommerce/pull/49752) +* Update - Update required and tested up to WP versions for the WordPress 6.6 release. [#49619](https://github.com/woocommerce/woocommerce/pull/49619) +* Update - Update Settings to disable Save button unless modifications are made. [#47444](https://github.com/woocommerce/woocommerce/pull/47444) +* Update - Update shipping method setup modal copy if the block-based local pickup is enabled [#48529](https://github.com/woocommerce/woocommerce/pull/48529) +* Update - Update Store Alert styles [#49174](https://github.com/woocommerce/woocommerce/pull/49174) +* Update - Update Store Alert widths to match main body [#48487](https://github.com/woocommerce/woocommerce/pull/48487) +* Update - Update the "Customer Account" block icon for the line style. [#49401](https://github.com/woocommerce/woocommerce/pull/49401) +* Update - Update the CYS opt-in messaging [#49894](https://github.com/woocommerce/woocommerce/pull/49894) +* Update - Update the footer section in "Add products" task [#49782](https://github.com/woocommerce/woocommerce/pull/49782) +* Update - Update WC Tasks in the WC Home. Rename to WooCommerce marketplace, add new browse marketplace, remove connect to woocomerce.com from inbox [#48128](https://github.com/woocommerce/woocommerce/pull/48128) +* Update - Utilize the new shared component to showcase WooPayments payment method logos. [#49300](https://github.com/woocommerce/woocommerce/pull/49300) +* Dev - Add Allure to Blocks e2e tests [#49228](https://github.com/woocommerce/woocommerce/pull/49228) +* Dev - Add daily checks for core e2e with PHP 8.1 and WP latest-1 [#48929](https://github.com/woocommerce/woocommerce/pull/48929) +* Dev - Add hook to customize the rendered receipt template [#48872](https://github.com/woocommerce/woocommerce/pull/48872) +* Dev - Add new CI workflow to trigger tests on demand. [#49674](https://github.com/woocommerce/woocommerce/pull/49674) +* Dev - Add support for e2e testing against external sites in CI [#49017](https://github.com/woocommerce/woocommerce/pull/49017) +* Dev - Another attempt to stabilize flaky Product Collection E2E tests. [#49638](https://github.com/woocommerce/woocommerce/pull/49638) +* Dev - Blocks E2E: Fix a flaky Product Collection test where accidental multiple edits occur and break the template saving step. [#49590](https://github.com/woocommerce/woocommerce/pull/49590) +* Dev - Blocks E2E: Fix DB snapshot removal step in setup script. [#49677](https://github.com/woocommerce/woocommerce/pull/49677) +* Dev - Build: speedup dependencies installation by disabling composer optimize autoloading by default. [#48980](https://github.com/woocommerce/woocommerce/pull/48980) +* Dev - CI: buffix for linting missing strict types directive. [#49015](https://github.com/woocommerce/woocommerce/pull/49015) +* Dev - CI: cleanup CI related command after fixing jobs matrix generation. [#49330](https://github.com/woocommerce/woocommerce/pull/49330) +* Dev - CI: code style fixes to pass linting in updated CI environment. [#49020](https://github.com/woocommerce/woocommerce/pull/49020) +* Dev - CI: improve flacky tests reporting job execution time. [#49665](https://github.com/woocommerce/woocommerce/pull/49665) +* Dev - CI: Re-group PHPUnit jobs. [#49443](https://github.com/woocommerce/woocommerce/pull/49443) +* Dev - CI: reduce running time for PHPUnit related jobs. [#49193](https://github.com/woocommerce/woocommerce/pull/49193) +* Dev - CI: tuning deps caching for playwright. [#49081](https://github.com/woocommerce/woocommerce/pull/49081) +* Dev - CI config: update changes lists to include wp-env config [#49626](https://github.com/woocommerce/woocommerce/pull/49626) +* Dev - Clean up unused files in plugins/woocommerce-blocks [#49319](https://github.com/woocommerce/woocommerce/pull/49319) +* Dev - Create a separate JS cart and checkout JavaScript bundle to improve performance. [#48010](https://github.com/woocommerce/woocommerce/pull/48010) +* Dev - CYS - Fix the "test_fetch_patterns_should_register_testimonials_category_as_reviews" tests. [#48719](https://github.com/woocommerce/woocommerce/pull/48719) +* Dev - Dropping select2 and point it to SelectWoo [#48731](https://github.com/woocommerce/woocommerce/pull/48731) +* Dev - E2E: enable slow tests reporting for blocks E2E tests. [#49367](https://github.com/woocommerce/woocommerce/pull/49367) +* Dev - E2E tests: fix basic spec for multiple environments [#49609](https://github.com/woocommerce/woocommerce/pull/49609) +* Dev - E2E tests: fix failing settings-tax e2e test [#48792](https://github.com/woocommerce/woocommerce/pull/48792) +* Dev - E2E tests: Fix flaky account email receiving test [#48957](https://github.com/woocommerce/woocommerce/pull/48957) +* Dev - E2E tests: Fix flaky connect to Woo.com test [#48926](https://github.com/woocommerce/woocommerce/pull/48926) +* Dev - E2E tests: Fix flaky filling regular price in the inventory tab [#49226](https://github.com/woocommerce/woocommerce/pull/49226) +* Dev - E2E tests: Fix flaky filling SKU field and CYS footer [#49191](https://github.com/woocommerce/woocommerce/pull/49191) +* Dev - E2E tests: Fix flaky Gutenberg, WC Services tests [#48916](https://github.com/woocommerce/woocommerce/pull/48916) +* Dev - E2E tests: Fix flaky Gutenberg tests [#48896](https://github.com/woocommerce/woocommerce/pull/48896) +* Dev - E2E tests: Fix flaky Gutenberg tests [#49548](https://github.com/woocommerce/woocommerce/pull/49548) +* Dev - E2E tests: Fix flaky logo picker waiting for response tests [#49451](https://github.com/woocommerce/woocommerce/pull/49451) +* Dev - E2E tests: Fix flaky merchant filling sku field in the new editor [#49134](https://github.com/woocommerce/woocommerce/pull/49134) +* Dev - E2E tests: Fix flaky merchant tests [#49381](https://github.com/woocommerce/woocommerce/pull/49381) +* Dev - E2E tests: Fix merchant settings general test [#48907](https://github.com/woocommerce/woocommerce/pull/48907) +* Dev - E2E tests: fix shopper checkout block test [#49596](https://github.com/woocommerce/woocommerce/pull/49596) +* Dev - E2E tests: fix some tests for WP 6.6 [#49634](https://github.com/woocommerce/woocommerce/pull/49634) +* Dev - E2E tests: tag different envs in e2e test suite to run in workflows [#48715](https://github.com/woocommerce/woocommerce/pull/48715) +* Dev - Final sanity check to make sure attributes are done saving [#48737](https://github.com/woocommerce/woocommerce/pull/48737) +* Dev - Fix broken syntax in e2e-guidelines.md. [#49018](https://github.com/woocommerce/woocommerce/pull/49018) +* Dev - Fix flaky orphaned refund test [#49741](https://github.com/woocommerce/woocommerce/pull/49741) +* Dev - Hide product filters overlay template part experimental feature from public release [#49564](https://github.com/woocommerce/woocommerce/pull/49564) +* Dev - In blocks codebase, export SITE_CURRENCY property with properties matching typescript definitions. [#48727](https://github.com/woocommerce/woocommerce/pull/48727) +* Dev - Lint new PHP files for strict types directive [#48943](https://github.com/woocommerce/woocommerce/pull/48943) +* Dev - Minor tooling tweaks (zip compression level, composer invocation) [#48857](https://github.com/woocommerce/woocommerce/pull/48857) +* Dev - Monorepo: enable Jest and babel-loader caching. [#49656](https://github.com/woocommerce/woocommerce/pull/49656) +* Dev - Monorepo: fix side-effects of setting strict mode for linting script. [#49436](https://github.com/woocommerce/woocommerce/pull/49436) +* Dev - Monorepo: minor tweaks in zip building script (use frozen lock file when installing dependecies). [#49640](https://github.com/woocommerce/woocommerce/pull/49640) +* Dev - Monorepo: refine approach to patching dependecies in favour of built-in pnpm functionality. [#49892](https://github.com/woocommerce/woocommerce/pull/49892) +* Dev - Monorepo: set strict mode for linting script. [#49366](https://github.com/woocommerce/woocommerce/pull/49366) +* Dev - Monorepo: tweak patching dependencies for better Webpack perfromance. [#49703](https://github.com/woocommerce/woocommerce/pull/49703) +* Dev - Move buildkite-test-collector to devDependencies [#49051](https://github.com/woocommerce/woocommerce/pull/49051) +* Dev - move docs out of main folder until subcategories are ready [#49354](https://github.com/woocommerce/woocommerce/pull/49354) +* Dev - Product Collection: add tracking for block usage [#46466](https://github.com/woocommerce/woocommerce/pull/46466) +* Dev - Remove performance tests from PR checks (leave on push to trunk) [#48927](https://github.com/woocommerce/woocommerce/pull/48927) +* Dev - Switch `render()` to `createRoot().render()` to use React 18 features. [#48858](https://github.com/woocommerce/woocommerce/pull/48858) +* Dev - Tests: pin wp-env core version to 6.5 (temporary until tests are fixed to pass with 6.6) [#49620](https://github.com/woocommerce/woocommerce/pull/49620) +* Dev - Tweaks related to caching Composer dependecies and Playwright downloads in CI. [#48865](https://github.com/woocommerce/woocommerce/pull/48865) +* Dev - Update Action Scheduler to 3.8.1 [#49483](https://github.com/woocommerce/woocommerce/pull/49483) +* Dev - Update a few e2e tests failing on the daily run [#49313](https://github.com/woocommerce/woocommerce/pull/49313) +* Dev - Update all values to be random so that retries don't fail on assertions [#48734](https://github.com/woocommerce/woocommerce/pull/48734) +* Dev - Updated CodeSniffer configuration to address conflicting rules. [#49183](https://github.com/woocommerce/woocommerce/pull/49183) +* Dev - Update Playwright from 1.44 to 1.45 [#49202](https://github.com/woocommerce/woocommerce/pull/49202) +* Tweak - Add admin_install_timestamp in WC_Tracker [#50076](https://github.com/woocommerce/woocommerce/pull/50076) +* Tweak - Add $wpdb->esc_like to the search criteria when searching for a product custom field name [#48949](https://github.com/woocommerce/woocommerce/pull/48949) +* Tweak - Add the initially installed WooCommerce version to the wp_options table [#49139](https://github.com/woocommerce/woocommerce/pull/49139) +* Tweak - Change CLIRunner namespace for better PSR compatibility. [#49390](https://github.com/woocommerce/woocommerce/pull/49390) +* Tweak - Equalize data in Order export with data in Client side CSV export [#49356](https://github.com/woocommerce/woocommerce/pull/49356) +* Tweak - Exclude coming soon patterns from block inserter [#48821](https://github.com/woocommerce/woocommerce/pull/48821) +* Tweak - Fix tip block syntax in register-product-collection.md [#49785](https://github.com/woocommerce/woocommerce/pull/49785) +* Tweak - Get tax line label instead of name in StoreAPI Order endpoint. [#48445](https://github.com/woocommerce/woocommerce/pull/48445) +* Tweak - Improve checks when offering to remove test orders [#49032](https://github.com/woocommerce/woocommerce/pull/49032) +* Tweak - Initialize BlockTemplatesController for block themes only. [#48905](https://github.com/woocommerce/woocommerce/pull/48905) +* Tweak - Product Collection: flatten telemetry query filters data to json string [#49680](https://github.com/woocommerce/woocommerce/pull/49680) +* Tweak - Remove enctype from verify email form [#48859](https://github.com/woocommerce/woocommerce/pull/48859) +* Tweak - Remove unneeded IE styling as IE is no longer supported [#49027](https://github.com/woocommerce/woocommerce/pull/49027) +* Tweak - Rename Google Listings and Ads with Google for WooCommerce [#47614](https://github.com/woocommerce/woocommerce/pull/47614) +* Tweak - Show Guest when there is no Customer name [#49594](https://github.com/woocommerce/woocommerce/pull/49594) +* Tweak - Trigger doing_it_wrong() when using HPOS query args for CPT order queries. [#47457](https://github.com/woocommerce/woocommerce/pull/47457) +* Tweak - Update text to Content right with image left pattern [#49792](https://github.com/woocommerce/woocommerce/pull/49792) +* Tweak - Update the "API enabled" entry in the System Status Report to clarify that it pertains to the Legacy REST API. [#48878](https://github.com/woocommerce/woocommerce/pull/48878) +* Tweak - Add placeholder options and validation to all checkout select inputs. [#49929](https://github.com/woocommerce/woocommerce/pull/49929) +* Performance - Load REST API namespaces only when needed. [#47704](https://github.com/woocommerce/woocommerce/pull/47704) +* Performance - Reduced number of recalculations on Store API cart routes [#48944](https://github.com/woocommerce/woocommerce/pull/48944) +* Enhancement - Add address title to edit/add buttons on My Account page [#49171](https://github.com/woocommerce/woocommerce/pull/49171) +* Enhancement - Added password field to block checkout (when enabled in settings) for new accounts to set a custom password. [#48985](https://github.com/woocommerce/woocommerce/pull/48985) +* Enhancement - Add required indication to login forms [#48743](https://github.com/woocommerce/woocommerce/pull/48743) +* Enhancement - Add scope attributes to the order table on My Account [#49201](https://github.com/woocommerce/woocommerce/pull/49201) +* Enhancement - Add strength meter to block checkout password field. [#49164](https://github.com/woocommerce/woocommerce/pull/49164) +* Enhancement - Allow blocks with parents in the "woocommerce" namespace to be added to the Checkout block without requiring them to be added to the "__experimental_woocommerce_blocks_add_data_attributes_to_block" hook. [#48543](https://github.com/woocommerce/woocommerce/pull/48543) +* Enhancement - Convert edit address link to a button on checkout [#49471](https://github.com/woocommerce/woocommerce/pull/49471) +* Enhancement - CYS: make the entire shuffle section clickable. [#48889](https://github.com/woocommerce/woocommerce/pull/48889) +* Enhancement - CYS: Remove iframe animation [#48941](https://github.com/woocommerce/woocommerce/pull/48941) +* Enhancement - Made the "return to cart" link (in the checkout block) hidden by default. [#48762](https://github.com/woocommerce/woocommerce/pull/48762) +* Enhancement - Provide the location context within the Product Collection block context [#44145](https://github.com/woocommerce/woocommerce/pull/44145) +* Enhancement - Updated block checkout and Store API stock handling so stock is only reserved when attempting payment for an order. [#49446](https://github.com/woocommerce/woocommerce/pull/49446) + = 9.1.4 2024-07-26 = **WooCommerce** @@ -8,7 +339,6 @@ * Fix - Hardening against XSS via the Product Button unescaped attribute. [#50010](https://github.com/woocommerce/woocommerce/pull/50010) * Fix - Enhance escaping for block attributes. [#50015](https://github.com/woocommerce/woocommerce/pull/50015) - = 9.1.2 2024-07-12 = **WooCommerce** @@ -5901,12 +6231,12 @@ * Dev - Revert work done in #4857 for automated shipping after OBW is completed #5971 * Add - Welcome modal when coming from Calypso #6004 * Enhancement - Add an a/b experiment for installing free business features #5786 -* Dev - Add `onChangeCallback` feature to the wc-admin `
` component #5786 +* Dev - Add `onChangeCallback` feature to the wc-admin `` component #5786 * Fix - Generate JSON translation chunks on plugin activation #6028 -* Dev - Add merchant email notifications #5922 +* Dev - Add merchant email notifications #5922 * Add - Email note to add first product. #6024 * Add - Note for users coming from Calypso. #6030 -* Enhancement - Add an "unread" indicator to inbox messages. #6047 +* Enhancement - Add an "unread" indicator to inbox messages. #6047 * Add - Manage activity from home screen inbox message. #6072 = 4.9.5 2022-03-10 = @@ -6709,7 +7039,7 @@ * Fix - The WCPay method not appearing as recommended sometimes #4345 * Fix - Removed URLSearchParams method #4501 * Fix - REST API collections schema. #4484 -* Fix - null issue in wpNavMenuClassChange #4513 🎉 gradosevic +* Fix - null issue in wpNavMenuClassChange #4513 🎉 gradosevic * Fix - RTL stylesheet loading for split code chunks. #4542 * Fix - Don't show store location step in tax and shipping tasks if the address has already been provided #4507 * Fix - Check for enabled methods before payment task completion #4530 @@ -6851,7 +7181,7 @@ * Dev - Fixed failing unit tests. #105 **WooCommerce Admin 1.2.3** -* Enhancement - Add onboarding payments note #4157 +* Enhancement - Add onboarding payments note #4157 * Enhancement - Marketing Inbox Note #4030 * Performance - Use Route based code splitting to reduce bundle size #4094 * Performance - trim down inbox note API request. #3977 @@ -7262,7 +7592,7 @@ * Dev - Add a filter `woocommerce_ajax_add_order_item_validation` to allow validations in `add_order_item` function. #24518 * Dev - Use `wc_get_cart_url` instead of `wc_get_page_permalink( 'cart' )` because former has a filter `woocommerce_get_cart_url` to allow customization. #24530 * Dev - New `woocommerce_product_after_tabs` action hook added. #24694 -* Dev - Enable append hashes on custom events (like ajax requests) #24665 +* Dev - Enable append hashes on custom events (like ajax requests) #24665 * Dev - Introduced `woocommerce_order_get_formatted_billing_address` and `woocommerce_order_get_formatted_shipping_address` filters. #24677 * Dev - WC_Abstract_Order::recalculate_coupons() is public now. #24740 * Dev - Added 'applied_coupon' trigger to checkout.js. #24406 @@ -7375,7 +7705,7 @@ * Tweak - Update the generate username setting description label to reflect how the username is actually generated. #23911 * Tweak - OBW: Adjust plugin highlight container sizes to avoid overlap. #23997 * Tweak - Round tax amounts late when the round at subtotal level setting is enabled to reduce rounding errors. #24024 -* Tweak - OBW: Now includes WooCommerce Admin as a recommended plugin. #24058 +* Tweak - OBW: Now includes WooCommerce Admin as a recommended plugin. #24058 * Template - Review and update all template files escaping. #23460 * Template - Remove mention of shipping section from the checkout/form-login.php template as shipping is not always a requirement for an order. #23941 * Template - Add new filter `woocommerce_before_thankyou` to the checkout/thankyou.php template. #23538 @@ -8047,7 +8377,7 @@ * Fix - Fix warning when using logger instance in woocommerce_logging_class filter. #21448 * Fix - Use uppercase "ID" when sorting product queries by ID. #21461 * Fix - Consistently escape the gateway ID in the checkout payment method template. #21439 -* Fix - Avoid treating HTTP 301 and 302 codes as failures for webhooks. #21491 +* Fix - Avoid treating HTTP 301 and 302 codes as failures for webhooks. #21491 * Fix - Add address_1 to shipping packages info in WC_Cart:: get_shipping_packages to make it work correctly in address formatting functions. #21493 * Fix - Don't fire two of the same action when saving shipping settings. #21494 * Fix - Remove double condition for address line 2 in `WC_Countries::get_default_address_fields`. #20629 @@ -8359,7 +8689,7 @@ * Fix - Delete orphaned variations after product import. #19378 * Fix - Ensure API credentials exist before defining PayPal refund support. #19380 * Fix - Force word-wrapping in the log viewer to prevent layout-breaking long lines. #19503 -* Fix - Removes permission checks that were preventing webhooks from displaying properly when no post object existed. #19508 +* Fix - Removes permission checks that were preventing webhooks from displaying properly when no post object existed. #19508 * Fix - Empty cart after completing PayPal payment. #19509 * Fix - Strip tags on aria-labels in Add to Cart template to prevent broken HTML. #19522 * Fix - Update post_modified date when saving products and variations but no other product data. #19595 @@ -8381,7 +8711,7 @@ * Fix - WC API should not try to create a product image when creating a product variation if an empty image is passed. #19971 * Fix - Force settings API settings to autoload by default. #19998 * Fix - Cart html5 validation events when using keyboard. #20001 -* Fix - Don't show stock status fields in external product quick-edit. #20005 +* Fix - Don't show stock status fields in external product quick-edit. #20005 * Fix - Prevent an infinite loop if 2 grouped products are linked. #20020 * Fix - Switch stock_status when manage stock gets changed to prevent being out of stock if stock quantity is > 0. #20021 * Fix - When duplicating variation, set the date to null. #20083 @@ -8643,7 +8973,7 @@ * Fix - is_visible should ensure product is is not trashed before returning true. * Fix - Return packages with no rates back to the cart so the shipping calculator is displayed even when the current country is not shippable. * Fix - Merge session and persistent carts when both exists after login. -* Fix - Remove "wc_error" query string after login. +* Fix - Remove "wc_error" query string after login. * Fix - Allow woocommerce_form_field() have 'custom_attributes' equal 0. * Fix - Bulk actions in status logs table. * Fix - Exclude add-to-cart from pagination links. @@ -8684,19 +9014,19 @@ * Fix - Removed class within class in admin meta boxes HTML. * Fix - Fixed wrong `flex-control-nav` selector scope in `add-to-cart-variation.js` * Fix - Allow variations to be added to cart from query string. -* Fix - Use `add_filter` for `comment_feed_where` hook. +* Fix - Use `add_filter` for `comment_feed_where` hook. * Fix - Change nocache_headers hook firing in the cache helper. * Fix - Coupon min/max spend based on displayed subtotal. * Fix - Fix event propagation on click in setup wizard and improve validation. * Fix - API - Change how line items are saved in API so calculations are correct. -* Tweak - Hide downloads from admin emails. +* Tweak - Hide downloads from admin emails. * Tweak - Set placeholder for variation lxwxh field to that of the parent. * Tweak - Improve the Add Payment Methods display so buttons are not shown when no payment methods support the feature. * Localization - Update NJ tax rate. * Localization - Add Belarusian ruble BYN. = 3.2.3 - 2017-11-02 = -* Fix - Fixed a conflict with some slider plugins due to sanitization of archive/term descriptions. +* Fix - Fixed a conflict with some slider plugins due to sanitization of archive/term descriptions. * Fix - Fixed a flexslider bug when there is only 1 image on the product page (no gallery). * Fix - Prevent potential notices when someone extends product tabs wrongly. * Fix - Fixed display of shipping calculator under some conditions. From e1e628ccf042b2a93205b16e277be6fd9edb785c Mon Sep 17 00:00:00 2001 From: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:18:20 +0100 Subject: [PATCH 065/185] [e2e tests] Fix flaky navigation to editor (#50841) --- .../e2e-fix-waitForResponse-editor-navigation | 4 ++++ plugins/woocommerce/tests/e2e-pw/utils/editor.js | 14 ++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 plugins/woocommerce/changelog/e2e-fix-waitForResponse-editor-navigation diff --git a/plugins/woocommerce/changelog/e2e-fix-waitForResponse-editor-navigation b/plugins/woocommerce/changelog/e2e-fix-waitForResponse-editor-navigation new file mode 100644 index 00000000000..4f73f5cc6c2 --- /dev/null +++ b/plugins/woocommerce/changelog/e2e-fix-waitForResponse-editor-navigation @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + + diff --git a/plugins/woocommerce/tests/e2e-pw/utils/editor.js b/plugins/woocommerce/tests/e2e-pw/utils/editor.js index 7b2a17ea71c..d2cf9d6dfe3 100644 --- a/plugins/woocommerce/tests/e2e-pw/utils/editor.js +++ b/plugins/woocommerce/tests/e2e-pw/utils/editor.js @@ -39,21 +39,23 @@ const getCanvas = async ( page ) => { }; const goToPageEditor = async ( { page } ) => { - await page.goto( 'wp-admin/post-new.php?post_type=page' ); - await disableWelcomeModal( { page } ); - await page.waitForResponse( + const responsePromise = page.waitForResponse( ( response ) => response.url().includes( '//page' ) && response.status() === 200 ); + await page.goto( 'wp-admin/post-new.php?post_type=page' ); + await disableWelcomeModal( { page } ); + await responsePromise; }; const goToPostEditor = async ( { page } ) => { - await page.goto( 'wp-admin/post-new.php' ); - await disableWelcomeModal( { page } ); - await page.waitForResponse( + const responsePromise = page.waitForResponse( ( response ) => response.url().includes( '//single' ) && response.status() === 200 ); + await page.goto( 'wp-admin/post-new.php' ); + await disableWelcomeModal( { page } ); + await responsePromise; }; const fillPageTitle = async ( page, title ) => { From 63f96eb5a850a6688e456418504d20d272f834e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Wytr=C4=99bowicz?= Date: Wed, 21 Aug 2024 21:59:42 +0200 Subject: [PATCH 066/185] Mark props with defaults as not required (#50816) --- packages/js/components/changelog/fix-50815-default-props | 4 ++++ packages/js/components/src/summary/number.js | 3 +-- packages/js/components/src/timeline/index.js | 2 +- packages/js/components/src/timeline/timeline-group.js | 4 ++-- packages/js/components/src/timeline/timeline-item.js | 2 +- .../client/analytics/components/report-table/index.js | 2 +- plugins/woocommerce/changelog/fix-50815-default-props | 4 ++++ 7 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 packages/js/components/changelog/fix-50815-default-props create mode 100644 plugins/woocommerce/changelog/fix-50815-default-props diff --git a/packages/js/components/changelog/fix-50815-default-props b/packages/js/components/changelog/fix-50815-default-props new file mode 100644 index 00000000000..980ba56f813 --- /dev/null +++ b/packages/js/components/changelog/fix-50815-default-props @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak + +Mark props with defaults as not required  diff --git a/packages/js/components/src/summary/number.js b/packages/js/components/src/summary/number.js index 8c1243311f8..aa10d0f9b01 100644 --- a/packages/js/components/src/summary/number.js +++ b/packages/js/components/src/summary/number.js @@ -192,8 +192,7 @@ SummaryNumber.propTypes = { /** * The type of the link */ - hrefType: PropTypes.oneOf( [ 'wp-admin', 'wc-admin', 'external' ] ) - .isRequired, + hrefType: PropTypes.oneOf( [ 'wp-admin', 'wc-admin', 'external' ] ), /** * Boolean describing whether the menu list is open. Only applies in mobile view, * and only applies to the toggle-able item (first in the list). diff --git a/packages/js/components/src/timeline/index.js b/packages/js/components/src/timeline/index.js index 5d0d67ce8c2..b5d7ddfb72b 100644 --- a/packages/js/components/src/timeline/index.js +++ b/packages/js/components/src/timeline/index.js @@ -99,7 +99,7 @@ Timeline.propTypes = { */ hideTimestamp: PropTypes.bool, } ) - ).isRequired, + ), /** * Defines how items should be grouped together. */ diff --git a/packages/js/components/src/timeline/timeline-group.js b/packages/js/components/src/timeline/timeline-group.js index 6ddcde8e02b..73ecbb8f922 100644 --- a/packages/js/components/src/timeline/timeline-group.js +++ b/packages/js/components/src/timeline/timeline-group.js @@ -94,8 +94,8 @@ TimelineGroup.propTypes = { */ hideTimestamp: PropTypes.bool, } ) - ).isRequired, - } ).isRequired, + ), + } ), /** * Defines how items should be ordered. */ diff --git a/packages/js/components/src/timeline/timeline-item.js b/packages/js/components/src/timeline/timeline-item.js index 59914878900..19961993e67 100644 --- a/packages/js/components/src/timeline/timeline-item.js +++ b/packages/js/components/src/timeline/timeline-item.js @@ -69,7 +69,7 @@ TimelineItem.propTypes = { * The PHP clock format string used to format times, see php.net/date. */ clockFormat: PropTypes.string, - } ).isRequired, + } ), }; export default TimelineItem; diff --git a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js index 6e049a9bacd..b486e059fdc 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js @@ -552,7 +552,7 @@ ReportTable.propTypes = { * Table data of that report. If it's not provided, it will be automatically * loaded via the provided `endpoint`. */ - tableData: PropTypes.object.isRequired, + tableData: PropTypes.object, /** * Properties to be added to the query sent to the report table endpoint. */ diff --git a/plugins/woocommerce/changelog/fix-50815-default-props b/plugins/woocommerce/changelog/fix-50815-default-props new file mode 100644 index 00000000000..8ed743c0e17 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50815-default-props @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Mark ReportTable tableData prop as not required From fa6ea00b3ce08435129d27d209cdbb0a711a5421 Mon Sep 17 00:00:00 2001 From: Lucas Date: Wed, 21 Aug 2024 17:25:27 -0300 Subject: [PATCH 067/185] Use stricter text selector on test (#50848) * Use stricter text selector Removes text ambiguity to avoid errors like "Strict mode violation resolved to 2 elements". For instance, it might search for "Settings", and there might be a menu "Foo Settings" which would resolve to 2 elements. This changes the behavior to match the exact test, instead of a substring. * Update page-loads.spec.js * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions --- .../changelog/50848-24-08-remove-selector-ambiguity | 4 ++++ .../tests/e2e-pw/tests/merchant/page-loads.spec.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 plugins/woocommerce/changelog/50848-24-08-remove-selector-ambiguity diff --git a/plugins/woocommerce/changelog/50848-24-08-remove-selector-ambiguity b/plugins/woocommerce/changelog/50848-24-08-remove-selector-ambiguity new file mode 100644 index 00000000000..958649b7ad2 --- /dev/null +++ b/plugins/woocommerce/changelog/50848-24-08-remove-selector-ambiguity @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Use stricter text selector on test \ No newline at end of file diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/page-loads.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/page-loads.spec.js index 50f86d283fb..d2ff9e34b11 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/page-loads.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/page-loads.spec.js @@ -206,7 +206,7 @@ for ( const currentPage of wcPages ) { } ) => { await page .locator( - `li.wp-menu-open > ul.wp-submenu > li:has-text("${ currentPage.subpages[ i ].name }")` + `li.wp-menu-open > ul.wp-submenu > li a:text-is("${ currentPage.subpages[ i ].name }")` ) .click(); From 35cdc6dc20d9686a1b72fc547ab2688db693e0ed Mon Sep 17 00:00:00 2001 From: Sam Seay Date: Thu, 22 Aug 2024 08:34:42 +0800 Subject: [PATCH 068/185] Use syncpack to lock pnpm version till we can fix issues (#50828) --- .syncpackrc | 2 +- package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/admin-e2e-tests/package.json | 2 +- packages/js/api-core-tests/package.json | 2 +- packages/js/api/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/api/package.json | 2 +- .../js/components/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/components/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/create-product-editor-block/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/create-woo-extension/package.json | 2 +- .../js/csv-export/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/csv-export/package.json | 2 +- .../js/currency/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/currency/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/customer-effort-score/package.json | 2 +- packages/js/data/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/data/package.json | 2 +- packages/js/date/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/date/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/dependency-extraction-webpack-plugin/package.json | 2 +- packages/js/e2e-core-tests/package.json | 2 +- packages/js/e2e-environment/package.json | 2 +- packages/js/e2e-utils/package.json | 2 +- .../eslint-plugin/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/eslint-plugin/package.json | 2 +- .../experimental/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/experimental/package.json | 2 +- packages/js/explat/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/explat/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/expression-evaluation/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/extend-cart-checkout-block/package.json | 2 +- packages/js/internal-e2e-builds/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/internal-js-tests/package.json | 2 +- packages/js/internal-style-build/package.json | 2 +- .../js/navigation/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/navigation/package.json | 2 +- .../js/notices/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/notices/package.json | 2 +- packages/js/number/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/number/package.json | 2 +- .../js/onboarding/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/onboarding/package.json | 2 +- .../remote-logging/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/remote-logging/package.json | 2 +- packages/js/tracks/changelog/50828-dev-constrain-pnpm-version | 4 ++++ packages/js/tracks/package.json | 2 +- plugins/woo-ai/changelog/50828-dev-constrain-pnpm-version | 4 ++++ plugins/woo-ai/package.json | 2 +- plugins/woocommerce-admin/package.json | 2 +- .../changelog/50828-dev-constrain-pnpm-version | 4 ++++ plugins/woocommerce-beta-tester/package.json | 2 +- plugins/woocommerce-blocks/package.json | 2 +- .../woocommerce/changelog/50828-dev-constrain-pnpm-version | 4 ++++ plugins/woocommerce/package.json | 2 +- tools/code-analyzer/package.json | 2 +- tools/compare-perf/package.json | 2 +- tools/monorepo-merge/package.json | 2 +- tools/monorepo-utils/package.json | 2 +- tools/package-release/package.json | 2 +- tools/release-posts/package.json | 2 +- tools/storybook/package.json | 2 +- 69 files changed, 147 insertions(+), 43 deletions(-) create mode 100644 packages/js/admin-e2e-tests/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/api/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/components/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/create-product-editor-block/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/create-woo-extension/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/csv-export/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/currency/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/customer-effort-score/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/data/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/date/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/dependency-extraction-webpack-plugin/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/eslint-plugin/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/experimental/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/explat/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/expression-evaluation/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/extend-cart-checkout-block/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/internal-js-tests/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/navigation/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/notices/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/number/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/onboarding/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/remote-logging/changelog/50828-dev-constrain-pnpm-version create mode 100644 packages/js/tracks/changelog/50828-dev-constrain-pnpm-version create mode 100644 plugins/woo-ai/changelog/50828-dev-constrain-pnpm-version create mode 100644 plugins/woocommerce-beta-tester/changelog/50828-dev-constrain-pnpm-version create mode 100644 plugins/woocommerce/changelog/50828-dev-constrain-pnpm-version diff --git a/.syncpackrc b/.syncpackrc index 800b3580f29..14b98ade137 100644 --- a/.syncpackrc +++ b/.syncpackrc @@ -12,7 +12,7 @@ "dependencies": [ "pnpm" ], - "pinVersion": "^9.1.0", + "pinVersion": "9.1.3", "packages": [ "**" ] diff --git a/package.json b/package.json index ed0db1d6f99..e01a7c1facb 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "packageManager": "pnpm@9.1.3", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "private": true, "repository": { diff --git a/packages/js/admin-e2e-tests/changelog/50828-dev-constrain-pnpm-version b/packages/js/admin-e2e-tests/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/admin-e2e-tests/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/admin-e2e-tests/package.json b/packages/js/admin-e2e-tests/package.json index 933b9d413a0..8113a5dbb03 100644 --- a/packages/js/admin-e2e-tests/package.json +++ b/packages/js/admin-e2e-tests/package.json @@ -6,7 +6,7 @@ "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/admin-e2e-tests/README.md", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "repository": { "type": "git", diff --git a/packages/js/api-core-tests/package.json b/packages/js/api-core-tests/package.json index a5c1a442eb4..a0667d48bfd 100644 --- a/packages/js/api-core-tests/package.json +++ b/packages/js/api-core-tests/package.json @@ -5,7 +5,7 @@ "main": "index.js", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "scripts": { "e2e": "jest", diff --git a/packages/js/api/changelog/50828-dev-constrain-pnpm-version b/packages/js/api/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/api/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/api/package.json b/packages/js/api/package.json index f428f5581ab..3cf9a7d739d 100644 --- a/packages/js/api/package.json +++ b/packages/js/api/package.json @@ -6,7 +6,7 @@ "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/api/README.md", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "repository": { "type": "git", diff --git a/packages/js/components/changelog/50828-dev-constrain-pnpm-version b/packages/js/components/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/components/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/components/package.json b/packages/js/components/package.json index fbb42628467..49781d18732 100644 --- a/packages/js/components/package.json +++ b/packages/js/components/package.json @@ -6,7 +6,7 @@ "license": "GPL-3.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/create-product-editor-block/changelog/50828-dev-constrain-pnpm-version b/packages/js/create-product-editor-block/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/create-product-editor-block/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/create-product-editor-block/package.json b/packages/js/create-product-editor-block/package.json index c21112cd09d..0e69b805f17 100644 --- a/packages/js/create-product-editor-block/package.json +++ b/packages/js/create-product-editor-block/package.json @@ -7,7 +7,7 @@ "main": "index.js", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "scripts": { "changelog": "composer install && composer exec -- changelogger" diff --git a/packages/js/create-woo-extension/changelog/50828-dev-constrain-pnpm-version b/packages/js/create-woo-extension/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/create-woo-extension/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/create-woo-extension/package.json b/packages/js/create-woo-extension/package.json index d7f3be1588f..6f5a61495b7 100644 --- a/packages/js/create-woo-extension/package.json +++ b/packages/js/create-woo-extension/package.json @@ -5,7 +5,7 @@ "main": "index.js", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "repository": { "type": "git", diff --git a/packages/js/csv-export/changelog/50828-dev-constrain-pnpm-version b/packages/js/csv-export/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/csv-export/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/csv-export/package.json b/packages/js/csv-export/package.json index 772d22e3c16..11a576f414f 100644 --- a/packages/js/csv-export/package.json +++ b/packages/js/csv-export/package.json @@ -6,7 +6,7 @@ "license": "GPL-3.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/currency/changelog/50828-dev-constrain-pnpm-version b/packages/js/currency/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/currency/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/currency/package.json b/packages/js/currency/package.json index 8e36f833963..a8b5ee2d4ce 100644 --- a/packages/js/currency/package.json +++ b/packages/js/currency/package.json @@ -11,7 +11,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/currency/README.md", "repository": { diff --git a/packages/js/customer-effort-score/changelog/50828-dev-constrain-pnpm-version b/packages/js/customer-effort-score/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/customer-effort-score/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/customer-effort-score/package.json b/packages/js/customer-effort-score/package.json index 110b88b358e..8c78924af57 100644 --- a/packages/js/customer-effort-score/package.json +++ b/packages/js/customer-effort-score/package.json @@ -10,7 +10,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/customer-effort-score/README.md", "repository": { diff --git a/packages/js/data/changelog/50828-dev-constrain-pnpm-version b/packages/js/data/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/data/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/data/package.json b/packages/js/data/package.json index c52f4e22698..178022e8a2b 100644 --- a/packages/js/data/package.json +++ b/packages/js/data/package.json @@ -11,7 +11,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/data/README.md", "repository": { diff --git a/packages/js/date/changelog/50828-dev-constrain-pnpm-version b/packages/js/date/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/date/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/date/package.json b/packages/js/date/package.json index 17e3f6152c8..d7f2fef1241 100644 --- a/packages/js/date/package.json +++ b/packages/js/date/package.json @@ -11,7 +11,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/date/README.md", "repository": { diff --git a/packages/js/dependency-extraction-webpack-plugin/changelog/50828-dev-constrain-pnpm-version b/packages/js/dependency-extraction-webpack-plugin/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/dependency-extraction-webpack-plugin/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/dependency-extraction-webpack-plugin/package.json b/packages/js/dependency-extraction-webpack-plugin/package.json index 18eb2cca63e..869625dd58b 100644 --- a/packages/js/dependency-extraction-webpack-plugin/package.json +++ b/packages/js/dependency-extraction-webpack-plugin/package.json @@ -10,7 +10,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/dependency-extraction-webpack-plugin/README.md", "repository": { diff --git a/packages/js/e2e-core-tests/package.json b/packages/js/e2e-core-tests/package.json index 7aa1cb71ad0..3f512664f5b 100644 --- a/packages/js/e2e-core-tests/package.json +++ b/packages/js/e2e-core-tests/package.json @@ -10,7 +10,7 @@ "license": "GPL-3.0+", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "main": "build/index.js", "module": "build-module/index.js", diff --git a/packages/js/e2e-environment/package.json b/packages/js/e2e-environment/package.json index f73aff3163c..f5f0afa6411 100644 --- a/packages/js/e2e-environment/package.json +++ b/packages/js/e2e-environment/package.json @@ -12,7 +12,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-environment/README.md", "bugs": { diff --git a/packages/js/e2e-utils/package.json b/packages/js/e2e-utils/package.json index d133e6c9a8f..1e47b320022 100644 --- a/packages/js/e2e-utils/package.json +++ b/packages/js/e2e-utils/package.json @@ -10,7 +10,7 @@ "license": "GPL-3.0+", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "main": "build/index.js", "module": "build-module/index.js", diff --git a/packages/js/eslint-plugin/changelog/50828-dev-constrain-pnpm-version b/packages/js/eslint-plugin/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/eslint-plugin/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/eslint-plugin/package.json b/packages/js/eslint-plugin/package.json index 7913b5a2b3e..4e5407484dc 100644 --- a/packages/js/eslint-plugin/package.json +++ b/packages/js/eslint-plugin/package.json @@ -6,7 +6,7 @@ "license": "GPL-2.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/experimental/changelog/50828-dev-constrain-pnpm-version b/packages/js/experimental/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/experimental/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/experimental/package.json b/packages/js/experimental/package.json index de525dbc624..3a2016f62ce 100644 --- a/packages/js/experimental/package.json +++ b/packages/js/experimental/package.json @@ -6,7 +6,7 @@ "license": "GPL-3.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/explat/changelog/50828-dev-constrain-pnpm-version b/packages/js/explat/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/explat/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/explat/package.json b/packages/js/explat/package.json index 376e4893ae4..377b1f25e98 100644 --- a/packages/js/explat/package.json +++ b/packages/js/explat/package.json @@ -6,7 +6,7 @@ "license": "GPL-2.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/expression-evaluation/changelog/50828-dev-constrain-pnpm-version b/packages/js/expression-evaluation/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/expression-evaluation/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/expression-evaluation/package.json b/packages/js/expression-evaluation/package.json index dc8316bd48c..0361729ee1c 100644 --- a/packages/js/expression-evaluation/package.json +++ b/packages/js/expression-evaluation/package.json @@ -12,7 +12,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/expression-evaluation/README.md", "repository": { diff --git a/packages/js/extend-cart-checkout-block/changelog/50828-dev-constrain-pnpm-version b/packages/js/extend-cart-checkout-block/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/extend-cart-checkout-block/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/extend-cart-checkout-block/package.json b/packages/js/extend-cart-checkout-block/package.json index 5695910fd8c..0e032c37149 100644 --- a/packages/js/extend-cart-checkout-block/package.json +++ b/packages/js/extend-cart-checkout-block/package.json @@ -5,7 +5,7 @@ "main": "index.js", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "repository": { "type": "git", diff --git a/packages/js/internal-e2e-builds/package.json b/packages/js/internal-e2e-builds/package.json index 49c4030cf54..ba7b5c89049 100644 --- a/packages/js/internal-e2e-builds/package.json +++ b/packages/js/internal-e2e-builds/package.json @@ -10,7 +10,7 @@ ], "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "bin": { "e2e-builds": "./build.js" diff --git a/packages/js/internal-js-tests/changelog/50828-dev-constrain-pnpm-version b/packages/js/internal-js-tests/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/internal-js-tests/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/internal-js-tests/package.json b/packages/js/internal-js-tests/package.json index 2a112db89d5..4f1049b8572 100644 --- a/packages/js/internal-js-tests/package.json +++ b/packages/js/internal-js-tests/package.json @@ -6,7 +6,7 @@ "license": "GPL-2.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/internal-js-tests/README.md", "repository": { diff --git a/packages/js/internal-style-build/package.json b/packages/js/internal-style-build/package.json index a777f36e231..9955a65abe9 100644 --- a/packages/js/internal-style-build/package.json +++ b/packages/js/internal-style-build/package.json @@ -6,7 +6,7 @@ "license": "GPL-2.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/navigation/changelog/50828-dev-constrain-pnpm-version b/packages/js/navigation/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/navigation/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/navigation/package.json b/packages/js/navigation/package.json index 903b2f3ef26..56c29eacab8 100644 --- a/packages/js/navigation/package.json +++ b/packages/js/navigation/package.json @@ -6,7 +6,7 @@ "license": "GPL-3.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/notices/changelog/50828-dev-constrain-pnpm-version b/packages/js/notices/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/notices/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/notices/package.json b/packages/js/notices/package.json index 0a649b7c7b3..b2c5ac704f8 100644 --- a/packages/js/notices/package.json +++ b/packages/js/notices/package.json @@ -6,7 +6,7 @@ "license": "GPL-2.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/number/changelog/50828-dev-constrain-pnpm-version b/packages/js/number/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/number/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/number/package.json b/packages/js/number/package.json index eebf9a2dede..44a2332d8df 100644 --- a/packages/js/number/package.json +++ b/packages/js/number/package.json @@ -6,7 +6,7 @@ "license": "GPL-3.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/onboarding/changelog/50828-dev-constrain-pnpm-version b/packages/js/onboarding/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/onboarding/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/onboarding/package.json b/packages/js/onboarding/package.json index 55825d51629..0521b2f2163 100644 --- a/packages/js/onboarding/package.json +++ b/packages/js/onboarding/package.json @@ -6,7 +6,7 @@ "license": "GPL-3.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/remote-logging/changelog/50828-dev-constrain-pnpm-version b/packages/js/remote-logging/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/remote-logging/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/remote-logging/package.json b/packages/js/remote-logging/package.json index 8bdc1cb7ace..c96e6ca3f18 100644 --- a/packages/js/remote-logging/package.json +++ b/packages/js/remote-logging/package.json @@ -6,7 +6,7 @@ "license": "GPL-2.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/packages/js/tracks/changelog/50828-dev-constrain-pnpm-version b/packages/js/tracks/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/packages/js/tracks/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/packages/js/tracks/package.json b/packages/js/tracks/package.json index 82aaf9e44ee..50fee1aac21 100644 --- a/packages/js/tracks/package.json +++ b/packages/js/tracks/package.json @@ -6,7 +6,7 @@ "license": "GPL-3.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "keywords": [ "wordpress", diff --git a/plugins/woo-ai/changelog/50828-dev-constrain-pnpm-version b/plugins/woo-ai/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/plugins/woo-ai/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/plugins/woo-ai/package.json b/plugins/woo-ai/package.json index c511404c47b..3083d8d3cfe 100644 --- a/plugins/woo-ai/package.json +++ b/plugins/woo-ai/package.json @@ -94,7 +94,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "lint-staged": { "*.php": [ diff --git a/plugins/woocommerce-admin/package.json b/plugins/woocommerce-admin/package.json index 436ea164243..8e84eeb1cd5 100644 --- a/plugins/woocommerce-admin/package.json +++ b/plugins/woocommerce-admin/package.json @@ -242,7 +242,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "config": { "ci": { diff --git a/plugins/woocommerce-beta-tester/changelog/50828-dev-constrain-pnpm-version b/plugins/woocommerce-beta-tester/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/plugins/woocommerce-beta-tester/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/plugins/woocommerce-beta-tester/package.json b/plugins/woocommerce-beta-tester/package.json index 2a8949e630c..503f1c40de8 100644 --- a/plugins/woocommerce-beta-tester/package.json +++ b/plugins/woocommerce-beta-tester/package.json @@ -91,7 +91,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "lint-staged": { "*.php": [ diff --git a/plugins/woocommerce-blocks/package.json b/plugins/woocommerce-blocks/package.json index 20f6ccec368..cd63f8a5ca4 100644 --- a/plugins/woocommerce-blocks/package.json +++ b/plugins/woocommerce-blocks/package.json @@ -253,7 +253,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "dependencies": { "@ariakit/react": "^0.4.4", diff --git a/plugins/woocommerce/changelog/50828-dev-constrain-pnpm-version b/plugins/woocommerce/changelog/50828-dev-constrain-pnpm-version new file mode 100644 index 00000000000..fdead95ceb5 --- /dev/null +++ b/plugins/woocommerce/changelog/50828-dev-constrain-pnpm-version @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix pnpm version to 9.1.3 to avoid dependency installation issues. \ No newline at end of file diff --git a/plugins/woocommerce/package.json b/plugins/woocommerce/package.json index 5abbacaef70..3e985a6f783 100644 --- a/plugins/woocommerce/package.json +++ b/plugins/woocommerce/package.json @@ -639,7 +639,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "browserslist": [ "> 0.1%", diff --git a/tools/code-analyzer/package.json b/tools/code-analyzer/package.json index 778644ae498..83210833493 100644 --- a/tools/code-analyzer/package.json +++ b/tools/code-analyzer/package.json @@ -40,7 +40,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "config": { "ci": { diff --git a/tools/compare-perf/package.json b/tools/compare-perf/package.json index 33c901973a3..430d64146e5 100644 --- a/tools/compare-perf/package.json +++ b/tools/compare-perf/package.json @@ -19,6 +19,6 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" } } diff --git a/tools/monorepo-merge/package.json b/tools/monorepo-merge/package.json index b5fe6b5a8b9..3a54f6badc3 100644 --- a/tools/monorepo-merge/package.json +++ b/tools/monorepo-merge/package.json @@ -63,7 +63,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "types": "dist/index.d.ts", "config": { diff --git a/tools/monorepo-utils/package.json b/tools/monorepo-utils/package.json index 92d0e48bc61..a98b66aa8b9 100644 --- a/tools/monorepo-utils/package.json +++ b/tools/monorepo-utils/package.json @@ -67,7 +67,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "config": { "ci": { diff --git a/tools/package-release/package.json b/tools/package-release/package.json index aba30fd4937..05fc14ff4b6 100644 --- a/tools/package-release/package.json +++ b/tools/package-release/package.json @@ -58,7 +58,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "types": "dist/index.d.ts", "config": { diff --git a/tools/release-posts/package.json b/tools/release-posts/package.json index 8220abf0a27..d005269258e 100644 --- a/tools/release-posts/package.json +++ b/tools/release-posts/package.json @@ -11,7 +11,7 @@ "license": "GPL-2.0-or-later", "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "devDependencies": { "@tsconfig/node16": "^1.0.4", diff --git a/tools/storybook/package.json b/tools/storybook/package.json index 5ac43d1193e..f45ca987fa9 100644 --- a/tools/storybook/package.json +++ b/tools/storybook/package.json @@ -19,7 +19,7 @@ }, "engines": { "node": "^20.11.1", - "pnpm": "^9.1.0" + "pnpm": "9.1.3" }, "bugs": { "url": "https://github.com/woocommerce/woocommerce/issues" From 8b62cf87e18a59da03c8ed2c0ff2b6adb28de853 Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Thu, 22 Aug 2024 08:57:46 +0800 Subject: [PATCH 069/185] Improve reset password check using or locator (#50823) * Update to use or locator * Changelog --- .../tweak-improve-reset-password-check | 4 +++ .../tests/merchant/lost-password.spec.js | 26 ++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 plugins/woocommerce/changelog/tweak-improve-reset-password-check diff --git a/plugins/woocommerce/changelog/tweak-improve-reset-password-check b/plugins/woocommerce/changelog/tweak-improve-reset-password-check new file mode 100644 index 00000000000..4f657552c2d --- /dev/null +++ b/plugins/woocommerce/changelog/tweak-improve-reset-password-check @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak + +Update reset password e2e to use or locator to check reset status diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/lost-password.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/lost-password.spec.js index e13f2d7c9ba..c38e848c541 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/lost-password.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/lost-password.spec.js @@ -19,20 +19,16 @@ test.describe( 'Can go to lost password page and submit the form', () => { .fill( admin.username ); await page.getByRole( 'button', { name: 'Get New Password' } ).click(); - try { - // For local testing, the email might not be sent, so we can ignore this error. - await expect( - page.getByText( - /The email could not be sent. Your site may not be correctly configured to send emails/i - ) - ).toBeVisible(); - } catch ( e ) { - // eslint-disable-next-line jest/no-try-expect - await page.waitForURL( '**/wp-login.php?checkemail=confirm' ); - // eslint-disable-next-line jest/no-try-expect - await expect( - page.getByText( /Check your email for the confirmation link/i ) - ).toBeVisible(); - } + const emailSentMessage = page.getByText( + 'check your email for the confirmation link' + ); + const emailNotSentMessage = page.getByText( + 'the email could not be sent' + ); + + // We don't have to care if the email was sent, we just want to know the button click attempts a reset. + await expect( + emailSentMessage.or( emailNotSentMessage ) + ).toBeVisible(); } ); } ); From b04f535a54274b1036b294c9940bcc33d4329ec1 Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Thu, 22 Aug 2024 10:27:35 +0800 Subject: [PATCH 070/185] [Beta tester] Add fake WooPayments completion tool (#50699) * Add woocommerce beta tester fake wcpay tool * Add changelog --- plugins/woocommerce-beta-tester/api/api.php | 1 + .../api/tools/class-fake-wcpayments.php | 62 ++++++++++++++++ .../api/tools/fake-woo-payments-gateway.php | 73 +++++++++++++++++++ .../changelog/add-beta-tester-tool-fake-wcpay | 4 + .../src/tools/commands/fake-woo-payments.js | 31 ++++++++ .../src/tools/commands/index.js | 9 +++ .../src/tools/data/actions.js | 25 +++++++ .../src/tools/data/reducer.js | 1 + .../src/tools/data/resolvers.js | 15 ++++ .../src/tools/data/selectors.js | 4 + 10 files changed, 225 insertions(+) create mode 100644 plugins/woocommerce-beta-tester/api/tools/class-fake-wcpayments.php create mode 100644 plugins/woocommerce-beta-tester/api/tools/fake-woo-payments-gateway.php create mode 100644 plugins/woocommerce-beta-tester/changelog/add-beta-tester-tool-fake-wcpay create mode 100644 plugins/woocommerce-beta-tester/src/tools/commands/fake-woo-payments.js diff --git a/plugins/woocommerce-beta-tester/api/api.php b/plugins/woocommerce-beta-tester/api/api.php index 16c1ef5e7cc..65b1d151aa8 100644 --- a/plugins/woocommerce-beta-tester/api/api.php +++ b/plugins/woocommerce-beta-tester/api/api.php @@ -55,6 +55,7 @@ require 'tools/trigger-update-callbacks.php'; require 'tools/reset-cys.php'; require 'tools/set-block-template-logging-threshold.php'; require 'tools/set-coming-soon-mode.php'; +require 'tools/fake-woo-payments-gateway.php'; require 'tracks/class-tracks-debug-log.php'; require 'features/features.php'; require 'rest-api-filters/class-wca-test-helper-rest-api-filters.php'; diff --git a/plugins/woocommerce-beta-tester/api/tools/class-fake-wcpayments.php b/plugins/woocommerce-beta-tester/api/tools/class-fake-wcpayments.php new file mode 100644 index 00000000000..01fa658c3a4 --- /dev/null +++ b/plugins/woocommerce-beta-tester/api/tools/class-fake-wcpayments.php @@ -0,0 +1,62 @@ +id = 'woocommerce_payments'; + $this->has_fields = true; + $this->method_title = 'WooPayments'; + $this->method_description = $this->get_method_description(); + + $this->description = ''; + $this->supports = array( + 'products', + 'refunds', + ); + } + + /** + * Returns true if the gateway needs additional configuration, false if it's ready to use. + * + * @see WC_Payment_Gateway::needs_setup + * @return bool + */ + public function needs_setup() { + return false; + } + + /** + * Check if the payment gateway is connected. This method is also used by + * external plugins to check if a connection has been established. + */ + public function is_connected() { + return true; + } + + /** + * Get the connection URL. + * Called directly by WooCommerce Core. + * + * @return string Connection URL. + */ + public function get_connection_url() { + return ''; + } + + /** + * Checks if the gateway is enabled, and also if it's configured enough to accept payments from customers. + * + * Use parent method value alongside other business rules to make the decision. + * + * @return bool Whether the gateway is enabled and ready to accept payments. + */ + public function is_available() { + return true; + } +} diff --git a/plugins/woocommerce-beta-tester/api/tools/fake-woo-payments-gateway.php b/plugins/woocommerce-beta-tester/api/tools/fake-woo-payments-gateway.php new file mode 100644 index 00000000000..c1f5d9f00e7 --- /dev/null +++ b/plugins/woocommerce-beta-tester/api/tools/fake-woo-payments-gateway.php @@ -0,0 +1,73 @@ + 'GET', + ) +); + +register_woocommerce_admin_test_helper_rest_route( + '/tools/fake-wcpay-completion/v1', + 'tools_set_fake_wcpay_completion', + array( + 'methods' => 'POST', + 'args' => array( + 'enabled' => array( + 'type' => 'enum', + 'enum' => array( 'yes', 'no' ), + 'required' => true, + 'description' => 'Whether to enable or disable fake WooPayments completion', + ), + ), + ) +); + +/** + * Get the current status of fake WooPayments completion. + */ +function tools_get_fake_wcpay_completion_status() { + return new WP_REST_Response( array( 'enabled' => get_option( 'wc_beta_tester_fake_wcpay_completion', 'no' ) ), 200 ); +} + +/** + * A tool to enable/disable fake WooPayments completion. + * + * @param WP_REST_Request $request Request object. + */ +function tools_set_fake_wcpay_completion( $request ) { + $enabled = $request->get_param( 'enabled' ); + update_option( 'wc_beta_tester_fake_wcpay_completion', $enabled ); + + return new WP_REST_Response( array( 'enabled' => $enabled ), 200 ); +} + + +if ( + 'yes' === get_option( 'wc_beta_tester_fake_wcpay_completion', 'no' ) && + class_exists( 'WC_Payment_Gateway_WCPay' ) +) { + add_filter( 'woocommerce_payment_gateways', 'tools_fake_wcpay' ); + add_filter( 'woocommerce_available_payment_gateways', 'tools_fake_wcpay' ); + + require_once dirname( __FILE__ ) . '/class-fake-wcpayments.php'; + + /** + * Fake WooPayments completion. + * + * @param array $gateways List of available payment gateways. + */ + function tools_fake_wcpay( $gateways ) { + $gateways['woocommerce_payments'] = new Fake_WCPayments(); + return $gateways; + } +} diff --git a/plugins/woocommerce-beta-tester/changelog/add-beta-tester-tool-fake-wcpay b/plugins/woocommerce-beta-tester/changelog/add-beta-tester-tool-fake-wcpay new file mode 100644 index 00000000000..35549787397 --- /dev/null +++ b/plugins/woocommerce-beta-tester/changelog/add-beta-tester-tool-fake-wcpay @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add fake WooPayments completion tool diff --git a/plugins/woocommerce-beta-tester/src/tools/commands/fake-woo-payments.js b/plugins/woocommerce-beta-tester/src/tools/commands/fake-woo-payments.js new file mode 100644 index 00000000000..ef41cf76fb6 --- /dev/null +++ b/plugins/woocommerce-beta-tester/src/tools/commands/fake-woo-payments.js @@ -0,0 +1,31 @@ +/** + * External dependencies + */ +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { STORE_KEY } from '../data/constants'; + +export const FAKE_WOO_PAYMENTS_ACTION_NAME = 'fakeWooPayments'; + +export const FakeWooPayments = () => { + const isEnabled = useSelect( ( select ) => + select( STORE_KEY ).getIsFakeWooPaymentsEnabled() + ); + const getDescription = () => { + switch ( isEnabled ) { + case 'yes': + return 'Enabled 🟢'; + case 'no': + return 'Disabled 🔴'; + case 'error': + return 'Error 🙁'; + default: + return 'Loading ...'; + } + }; + + return
{ getDescription() }
; +}; diff --git a/plugins/woocommerce-beta-tester/src/tools/commands/index.js b/plugins/woocommerce-beta-tester/src/tools/commands/index.js index 6283f0e35a8..66ba187eefa 100644 --- a/plugins/woocommerce-beta-tester/src/tools/commands/index.js +++ b/plugins/woocommerce-beta-tester/src/tools/commands/index.js @@ -15,6 +15,10 @@ import { SetComingSoonMode, UPDATE_COMING_SOON_MODE_ACTION_NAME, } from './set-coming-soon-mode'; +import { + FakeWooPayments, + FAKE_WOO_PAYMENTS_ACTION_NAME, +} from './fake-woo-payments'; import { UPDATE_WCCOM_REQUEST_ERRORS_MODE, @@ -97,4 +101,9 @@ export default [ description: , action: UPDATE_WCCOM_REQUEST_ERRORS_MODE, }, + { + command: 'Toggle Fake WooPayments Completion Status', + description: , + action: FAKE_WOO_PAYMENTS_ACTION_NAME, + }, ]; diff --git a/plugins/woocommerce-beta-tester/src/tools/data/actions.js b/plugins/woocommerce-beta-tester/src/tools/data/actions.js index e4455482694..e2cc1e67cb4 100644 --- a/plugins/woocommerce-beta-tester/src/tools/data/actions.js +++ b/plugins/woocommerce-beta-tester/src/tools/data/actions.js @@ -282,3 +282,28 @@ export function* updateWccomRequestErrorsMode( params ) { } ); } ); } + +export function* fakeWooPayments( params ) { + yield runCommand( 'Toggle Fake WooPayments Completion', function* () { + const newStatus = params.enabled === 'yes' ? 'no' : 'yes'; + + yield apiFetch( { + path: API_NAMESPACE + '/tools/fake-wcpay-completion/v1', + method: 'POST', + data: { + enabled: newStatus, + }, + } ); + + yield updateCommandParams( 'fakeWooPayments', { + enabled: newStatus, + } ); + + yield updateMessage( + 'Toggle Fake WooPayments Completion', + `Fake WooPayments completion ${ + newStatus === 'yes' ? 'disabled' : 'enabled' + }` + ); + } ); +} diff --git a/plugins/woocommerce-beta-tester/src/tools/data/reducer.js b/plugins/woocommerce-beta-tester/src/tools/data/reducer.js index 2545784a6db..481561117d8 100644 --- a/plugins/woocommerce-beta-tester/src/tools/data/reducer.js +++ b/plugins/woocommerce-beta-tester/src/tools/data/reducer.js @@ -14,6 +14,7 @@ const DEFAULT_STATE = { updateBlockTemplateLoggingThreshold: {}, runSelectedUpdateCallbacks: {}, updateWccomRequestErrorsMode: {}, + fakeWooPayments: {}, }, status: '', dbUpdateVersions: [], diff --git a/plugins/woocommerce-beta-tester/src/tools/data/resolvers.js b/plugins/woocommerce-beta-tester/src/tools/data/resolvers.js index 81065ce3170..0e839b27760 100644 --- a/plugins/woocommerce-beta-tester/src/tools/data/resolvers.js +++ b/plugins/woocommerce-beta-tester/src/tools/data/resolvers.js @@ -18,6 +18,7 @@ import { UPDATE_BLOCK_TEMPLATE_LOGGING_THRESHOLD_ACTION_NAME } from '../commands import { UPDATE_COMING_SOON_MODE_ACTION_NAME } from '../commands/set-coming-soon-mode'; import { TRIGGER_UPDATE_CALLBACKS_ACTION_NAME } from '../commands/trigger-update-callbacks'; import { UPDATE_WCCOM_REQUEST_ERRORS_MODE } from '../commands/set-wccom-request-errors'; +import { FAKE_WOO_PAYMENTS_ACTION_NAME } from '../commands/fake-woo-payments'; export function* getCronJobs() { const path = `${ API_NAMESPACE }/tools/get-cron-list/v1`; @@ -135,3 +136,17 @@ export function* getWccomRequestErrorsMode() { throw new Error( error ); } } + +export function* getIsFakeWooPaymentsEnabled() { + try { + const response = yield apiFetch( { + path: API_NAMESPACE + '/tools/fake-wcpay-completion/v1', + method: 'GET', + } ); + yield updateCommandParams( FAKE_WOO_PAYMENTS_ACTION_NAME, { + enabled: response.enabled || 'no', + } ); + } catch ( error ) { + throw new Error( error ); + } +} diff --git a/plugins/woocommerce-beta-tester/src/tools/data/selectors.js b/plugins/woocommerce-beta-tester/src/tools/data/selectors.js index b53025ff4b1..bca03b9bbf9 100644 --- a/plugins/woocommerce-beta-tester/src/tools/data/selectors.js +++ b/plugins/woocommerce-beta-tester/src/tools/data/selectors.js @@ -41,3 +41,7 @@ export function getComingSoonMode( state ) { export function getWccomRequestErrorsMode( state ) { return state.params.updateWccomRequestErrorsMode.mode; } + +export function getIsFakeWooPaymentsEnabled( state ) { + return state.params.fakeWooPayments.enabled; +} From 0a60c3c5ec9b4830ab7d4e3817354f25bec597c3 Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Thu, 22 Aug 2024 11:34:23 +0800 Subject: [PATCH 071/185] Add e2e tests to confirm that the store is in coming soon mode after completing the core profiler (#50784) * Update core profiler setup e2e to handle coming soon mode This adds a new test to confirm that the store is in coming soon mode after completing the core profiler. Additionally, it adds a new test to confirm that the store is in coming soon mode after skipping the core profiler. These changes are necessary to ensure that the core profiler setup works correctly when the store is in coming soon mode. * Add changefile(s) from automation for the following project(s): woocommerce * Include coming soon test case in core profiler steps --------- Co-authored-by: github-actions --- .../changelog/50784-add-coming-soon-mode-e2e | 4 ++ .../activate-and-setup/core-profiler.spec.js | 43 ++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 plugins/woocommerce/changelog/50784-add-coming-soon-mode-e2e diff --git a/plugins/woocommerce/changelog/50784-add-coming-soon-mode-e2e b/plugins/woocommerce/changelog/50784-add-coming-soon-mode-e2e new file mode 100644 index 00000000000..bfa1b361fd6 --- /dev/null +++ b/plugins/woocommerce/changelog/50784-add-coming-soon-mode-e2e @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Add e2e tests to confirm that the store is in coming soon mode after completing the core profiler \ No newline at end of file diff --git a/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js index 0f4204f2075..e2f3718c0f5 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/activate-and-setup/core-profiler.spec.js @@ -1,8 +1,22 @@ -const { test, expect } = require( '@playwright/test' ); +const { test, expect, request } = require( '@playwright/test' ); +const { setOption } = require( '../../utils/options' ); test.describe( 'Store owner can complete the core profiler', () => { test.use( { storageState: process.env.ADMINSTATE } ); + test.beforeAll( async ( { baseURL } ) => { + try { + await setOption( + request, + baseURL, + 'woocommerce_coming_soon', + 'no' + ); + } catch ( error ) { + console.log( error ); + } + } ); + test( 'Can complete the core profiler skipping extension install', async ( { page, } ) => { @@ -393,12 +407,32 @@ test.describe( 'Store owner can complete the core profiler', () => { page.getByLabel( 'Delete Pinterest for' ) ).toBeHidden(); } ); + + await test.step( 'Confirm that the store is in coming soon mode after completing the core profiler', async () => { + await page.goto( 'wp-admin/admin.php?page=wc-admin' ); + await expect( + page.getByRole( 'menuitem', { name: 'Store coming soon' } ) + ).toBeVisible(); + } ); } ); } ); test.describe( 'Store owner can skip the core profiler', () => { test.use( { storageState: process.env.ADMINSTATE } ); + test.beforeAll( async ( { baseURL } ) => { + try { + await setOption( + request, + baseURL, + 'woocommerce_coming_soon', + 'no' + ); + } catch ( error ) { + console.log( error ); + } + } ); + test( 'Can click skip guided setup', async ( { page } ) => { await page.goto( 'wp-admin/admin.php?page=wc-admin&path=%2Fsetup-wizard' @@ -426,6 +460,13 @@ test.describe( 'Store owner can skip the core profiler', () => { name: 'Welcome to WooCommerce Core E2E Test Suite', } ) ).toBeVisible(); + + await test.step( 'Confirm that the store is in coming soon mode after skipping the core profiler', async () => { + await page.goto( 'wp-admin/admin.php?page=wc-admin' ); + await expect( + page.getByRole( 'menuitem', { name: 'Store coming soon' } ) + ).toBeVisible(); + } ); } ); test( 'Can connect to WooCommerce.com', async ( { page } ) => { From ae6f7837b224bd39005e65c80420b0c1a83a4201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Rinc=C3=B3n?= Date: Thu, 22 Aug 2024 09:47:03 +0200 Subject: [PATCH 072/185] CYS - Move the `ai/products` endpoint to woocommerce admin API (#50396) * CYS - Move the ai/store-title endpoint to woocommerce admin api * Add middleware and callback * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint error * CYS - Move the ai/business-description endpoint to woocommerce admin API * CYS - Move the ai/store-info endpoint to woocommerce admin API * Update endpoint * CYS - Move the ai/images endpoint to woocommerce admin API * CYS - Move the `ai/patterns` endpoint to woocommerce admin API * CYS - Move the `ai/product` endpoint to woocommerce admin API * CYS - Move the `ai/products` endpoint to woocommerce admin API * Add changefile(s) from automation for the following project(s): woocommerce * Add changefile(s) from automation for the following project(s): woocommerce-beta-tester, woocommerce * Add changefile(s) from automation for the following project(s): woocommerce * Fix merge issues * Add strict types * Start extending from AIEndpoint --------- Co-authored-by: github-actions --- .../design-with-ai/services.ts | 4 +- .../50396-48150-move-products-endpoint | 4 + .../woocommerce/src/Admin/API/AI/Products.php | 128 +++++++++++++++ plugins/woocommerce/src/Admin/API/Init.php | 1 + .../src/StoreApi/Routes/V1/AI/Middleware.php | 50 ------ .../src/StoreApi/Routes/V1/AI/Products.php | 153 ------------------ .../src/StoreApi/RoutesController.php | 4 +- .../src/StoreApi/SchemaController.php | 1 - .../StoreApi/Schemas/V1/AI/ProductsSchema.php | 48 ------ 9 files changed, 136 insertions(+), 257 deletions(-) create mode 100644 plugins/woocommerce/changelog/50396-48150-move-products-endpoint create mode 100644 plugins/woocommerce/src/Admin/API/AI/Products.php delete mode 100644 plugins/woocommerce/src/StoreApi/Routes/V1/AI/Middleware.php delete mode 100644 plugins/woocommerce/src/StoreApi/Routes/V1/AI/Products.php delete mode 100644 plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ProductsSchema.php diff --git a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts index 3e16f4683ac..b4008b58dde 100644 --- a/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts +++ b/plugins/woocommerce-admin/client/customize-store/design-with-ai/services.ts @@ -220,7 +220,7 @@ const resetPatternsAndProducts = () => async () => { method: 'DELETE', } ), apiFetch( { - path: '/wc/private/ai/products', + path: '/wc-admin/ai/products', method: 'DELETE', } ), ] ); @@ -278,7 +278,7 @@ export const updateStorePatterns = async ( additional_errors?: unknown[]; } >( [ apiFetch( { - path: '/wc/private/ai/products', + path: '/wc-admin/ai/products', method: 'POST', data: { business_description: diff --git a/plugins/woocommerce/changelog/50396-48150-move-products-endpoint b/plugins/woocommerce/changelog/50396-48150-move-products-endpoint new file mode 100644 index 00000000000..3a397780d9a --- /dev/null +++ b/plugins/woocommerce/changelog/50396-48150-move-products-endpoint @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +CYS - Move the "ai/products" endpoint to woocommerce admin API. \ No newline at end of file diff --git a/plugins/woocommerce/src/Admin/API/AI/Products.php b/plugins/woocommerce/src/Admin/API/AI/Products.php new file mode 100644 index 00000000000..e764777ca76 --- /dev/null +++ b/plugins/woocommerce/src/Admin/API/AI/Products.php @@ -0,0 +1,128 @@ +register( + array( + array( + 'methods' => \WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'generate_products_content' ), + 'permission_callback' => array( Middleware::class, 'is_authorized' ), + 'args' => array( + 'business_description' => array( + 'description' => __( 'The business description for a given store.', 'woocommerce' ), + 'type' => 'string', + ), + 'images' => array( + 'description' => __( 'The images for a given store.', 'woocommerce' ), + 'type' => 'object', + ), + ), + ), + array( + 'methods' => \WP_REST_Server::DELETABLE, + 'callback' => array( $this, 'delete_products' ), + 'permission_callback' => array( Middleware::class, 'is_authorized' ), + ), + ) + ); + } + + /** + * Generate the content for the products. + * + * @param WP_REST_Request $request Request object. + * + * @return WP_Error|WP_REST_Response + */ + public function generate_products_content( WP_REST_Request $request ) { + $allow_ai_connection = get_option( 'woocommerce_blocks_allow_ai_connection' ); + + if ( ! $allow_ai_connection ) { + return rest_ensure_response( + new WP_Error( + 'ai_connection_not_allowed', + __( 'AI content generation is not allowed on this store. Update your store settings if you wish to enable this feature.', 'woocommerce' ) + ) + ); + } + + $business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) ); + + if ( empty( $business_description ) ) { + $business_description = get_option( 'woo_ai_describe_store_description' ); + } + + $ai_connection = new Connection(); + + $site_id = $ai_connection->get_site_id(); + + if ( is_wp_error( $site_id ) ) { + return $site_id; + } + + $token = $ai_connection->get_jwt_token( $site_id ); + + if ( is_wp_error( $token ) ) { + return $token; + } + + $images = $request['images']; + + $populate_products = ( new UpdateProducts() )->generate_content( $ai_connection, $token, $images, $business_description ); + + if ( is_wp_error( $populate_products ) ) { + return $populate_products; + } + + if ( ! isset( $populate_products['product_content'] ) ) { + return new WP_Error( 'product_content_not_found', __( 'Product content not found.', 'woocommerce' ) ); + } + + $product_content = $populate_products['product_content']; + + $item = array( + 'ai_content_generated' => true, + 'product_content' => $product_content, + ); + + return rest_ensure_response( $item ); + } + + /** + * Remove products generated by AI. + * + * @return WP_Error|WP_REST_Response + */ + public function delete_products() { + ( new UpdateProducts() )->reset_products_content(); + return rest_ensure_response( array( 'removed' => true ) ); + } +} diff --git a/plugins/woocommerce/src/Admin/API/Init.php b/plugins/woocommerce/src/Admin/API/Init.php index 9ea331a9ef7..65522e28501 100644 --- a/plugins/woocommerce/src/Admin/API/Init.php +++ b/plugins/woocommerce/src/Admin/API/Init.php @@ -92,6 +92,7 @@ class Init { 'Automattic\WooCommerce\Admin\API\AI\Images', 'Automattic\WooCommerce\Admin\API\AI\Patterns', 'Automattic\WooCommerce\Admin\API\AI\Product', + 'Automattic\WooCommerce\Admin\API\AI\Products', ); } diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Middleware.php b/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Middleware.php deleted file mode 100644 index 33a2d8ece7f..00000000000 --- a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Middleware.php +++ /dev/null @@ -1,50 +0,0 @@ -getErrorCode(), - $error->getMessage(), - array( 'status' => $error->getCode() ) - ); - } - - $allow_ai_connection = get_option( 'woocommerce_blocks_allow_ai_connection' ); - - if ( ! $allow_ai_connection ) { - try { - throw new RouteException( 'ai_connection_not_allowed', __( 'AI content generation is not allowed on this store. Update your store settings if you wish to enable this feature.', 'woocommerce' ), 403 ); - } catch ( RouteException $error ) { - return new \WP_Error( - $error->getErrorCode(), - $error->getMessage(), - array( 'status' => $error->getCode() ) - ); - } - } - - return true; - } -} diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Products.php b/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Products.php deleted file mode 100644 index 086b8a61636..00000000000 --- a/plugins/woocommerce/src/StoreApi/Routes/V1/AI/Products.php +++ /dev/null @@ -1,153 +0,0 @@ - \WP_REST_Server::CREATABLE, - 'callback' => [ $this, 'get_response' ], - 'permission_callback' => [ Middleware::class, 'is_authorized' ], - 'args' => [ - 'business_description' => [ - 'description' => __( 'The business description for a given store.', 'woocommerce' ), - 'type' => 'string', - ], - 'images' => [ - 'description' => __( 'The images for a given store.', 'woocommerce' ), - 'type' => 'object', - ], - ], - ], - [ - 'methods' => \WP_REST_Server::DELETABLE, - 'callback' => [ $this, 'get_response' ], - 'permission_callback' => [ Middleware::class, 'is_authorized' ], - ], - 'schema' => [ $this->schema, 'get_public_item_schema' ], - 'allow_batch' => [ 'v1' => true ], - ]; - } - - /** - * Generate the content for the products. - * - * @param \WP_REST_Request $request Request object. - * - * @return bool|string|\WP_Error|\WP_REST_Response - */ - protected function get_route_post_response( \WP_REST_Request $request ) { - $allow_ai_connection = get_option( 'woocommerce_blocks_allow_ai_connection' ); - - if ( ! $allow_ai_connection ) { - return rest_ensure_response( - $this->error_to_response( - new \WP_Error( - 'ai_connection_not_allowed', - __( 'AI content generation is not allowed on this store. Update your store settings if you wish to enable this feature.', 'woocommerce' ) - ) - ) - ); - } - - $business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) ); - - if ( empty( $business_description ) ) { - $business_description = get_option( 'woo_ai_describe_store_description' ); - } - - $ai_connection = new Connection(); - - $site_id = $ai_connection->get_site_id(); - - if ( is_wp_error( $site_id ) ) { - return $this->error_to_response( $site_id ); - } - - $token = $ai_connection->get_jwt_token( $site_id ); - - if ( is_wp_error( $token ) ) { - return $this->error_to_response( $token ); - } - - $images = $request['images']; - - $populate_products = ( new UpdateProducts() )->generate_content( $ai_connection, $token, $images, $business_description ); - - if ( is_wp_error( $populate_products ) ) { - return $this->error_to_response( $populate_products ); - } - - if ( ! isset( $populate_products['product_content'] ) ) { - return $this->error_to_response( new \WP_Error( 'product_content_not_found', __( 'Product content not found.', 'woocommerce' ) ) ); - } - - $product_content = $populate_products['product_content']; - - $item = array( - 'ai_content_generated' => true, - 'product_content' => $product_content, - ); - - return rest_ensure_response( $item ); - } - - /** - * Remove products generated by AI. - * - * @param \WP_REST_Request $request Request object. - * - * @return bool|string|\WP_Error|\WP_REST_Response - */ - protected function get_route_delete_response( \WP_REST_Request $request ) { - ( new UpdateProducts() )->reset_products_content(); - return rest_ensure_response( array( 'removed' => true ) ); - } -} diff --git a/plugins/woocommerce/src/StoreApi/RoutesController.php b/plugins/woocommerce/src/StoreApi/RoutesController.php index 1b88b70daa0..5ae47b7ba75 100644 --- a/plugins/woocommerce/src/StoreApi/RoutesController.php +++ b/plugins/woocommerce/src/StoreApi/RoutesController.php @@ -66,10 +66,8 @@ class RoutesController { Routes\V1\ProductsById::IDENTIFIER => Routes\V1\ProductsById::class, Routes\V1\ProductsBySlug::IDENTIFIER => Routes\V1\ProductsBySlug::class, ], - // @todo Migrate internal AI routes to WooCommerce Core codebase. 'private' => [ - Routes\V1\AI\Products::IDENTIFIER => Routes\V1\AI\Products::class, - Routes\V1\Patterns::IDENTIFIER => Routes\V1\Patterns::class, + Routes\V1\Patterns::IDENTIFIER => Routes\V1\Patterns::class, ], ]; } diff --git a/plugins/woocommerce/src/StoreApi/SchemaController.php b/plugins/woocommerce/src/StoreApi/SchemaController.php index 252b475b584..f0a4a4b4718 100644 --- a/plugins/woocommerce/src/StoreApi/SchemaController.php +++ b/plugins/woocommerce/src/StoreApi/SchemaController.php @@ -54,7 +54,6 @@ class SchemaController { Schemas\V1\ProductCategorySchema::IDENTIFIER => Schemas\V1\ProductCategorySchema::class, Schemas\V1\ProductCollectionDataSchema::IDENTIFIER => Schemas\V1\ProductCollectionDataSchema::class, Schemas\V1\ProductReviewSchema::IDENTIFIER => Schemas\V1\ProductReviewSchema::class, - Schemas\V1\AI\ProductsSchema::IDENTIFIER => Schemas\V1\AI\ProductsSchema::class, Schemas\V1\PatternsSchema::IDENTIFIER => Schemas\V1\PatternsSchema::class, ], ]; diff --git a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ProductsSchema.php b/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ProductsSchema.php deleted file mode 100644 index 114df7807af..00000000000 --- a/plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ProductsSchema.php +++ /dev/null @@ -1,48 +0,0 @@ - $item['ai_content_generated'], - 'product_content' => $item['product_content'], - ]; - } -} From 285348841015ae94055f5cc06945025eda3a6203 Mon Sep 17 00:00:00 2001 From: Praveen Date: Thu, 22 Aug 2024 00:59:34 -0700 Subject: [PATCH 073/185] Conditionally set new order email sent meta field (#50858) * Add conditional logic to set email sent metafield * Add changelog file for fix being submitted --- .../changelog/fix-conditionally-set-new-order-metafield | 4 ++++ .../includes/emails/class-wc-email-new-order.php | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-conditionally-set-new-order-metafield diff --git a/plugins/woocommerce/changelog/fix-conditionally-set-new-order-metafield b/plugins/woocommerce/changelog/fix-conditionally-set-new-order-metafield new file mode 100644 index 00000000000..40da44a369b --- /dev/null +++ b/plugins/woocommerce/changelog/fix-conditionally-set-new-order-metafield @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Conditionally set new order email sent meta field diff --git a/plugins/woocommerce/includes/emails/class-wc-email-new-order.php b/plugins/woocommerce/includes/emails/class-wc-email-new-order.php index 3451c64b3a3..33a49ebce34 100644 --- a/plugins/woocommerce/includes/emails/class-wc-email-new-order.php +++ b/plugins/woocommerce/includes/emails/class-wc-email-new-order.php @@ -109,10 +109,11 @@ if ( ! class_exists( 'WC_Email_New_Order' ) ) : } if ( $this->is_enabled() && $this->get_recipient() ) { - $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); - - $order->update_meta_data( '_new_order_email_sent', 'true' ); - $order->save(); + $email_sent_successfully = $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); + if ( $email_sent_successfully ) { + $order->update_meta_data( '_new_order_email_sent', 'true' ); + $order->save(); + } } $this->restore_locale(); From 2c0d9e06226617a3f601d0778302099f6b044ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Thu, 22 Aug 2024 13:47:41 +0200 Subject: [PATCH 074/185] Store API: Add test coverage for Product Reviews endpoint (#50639) * Store API: Add test coverage for Product Reviews endpoint * Add changelog file * Use assertSame() instead of assertEquals() * Linting * Fix category_id param test --- .../fix-42064-product-reviews-endpoint-tests | 5 + .../php/src/Blocks/Helpers/FixtureData.php | 16 +++ .../Blocks/StoreApi/Routes/ProductReviews.php | 129 ++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-42064-product-reviews-endpoint-tests create mode 100644 plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/ProductReviews.php diff --git a/plugins/woocommerce/changelog/fix-42064-product-reviews-endpoint-tests b/plugins/woocommerce/changelog/fix-42064-product-reviews-endpoint-tests new file mode 100644 index 00000000000..8193d364b24 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-42064-product-reviews-endpoint-tests @@ -0,0 +1,5 @@ +Significance: patch +Type: dev +Comment: Store API: Add test coverage for Product Reviews endpoint + + diff --git a/plugins/woocommerce/tests/php/src/Blocks/Helpers/FixtureData.php b/plugins/woocommerce/tests/php/src/Blocks/Helpers/FixtureData.php index f1342196129..e31a24cf7ea 100644 --- a/plugins/woocommerce/tests/php/src/Blocks/Helpers/FixtureData.php +++ b/plugins/woocommerce/tests/php/src/Blocks/Helpers/FixtureData.php @@ -194,6 +194,22 @@ class FixtureData { return $return; } + /** + * Create a product category and return the result. + * + * @param array $props Category props. + * @return array + */ + public function get_product_category( $props ) { + $category_name = $props['name'] ?? 'Test Category'; + + return wp_insert_term( + $category_name, + 'product_cat', + $props + ); + } + /** * Create a coupon and return the result. * diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/ProductReviews.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/ProductReviews.php new file mode 100644 index 00000000000..e11497c5cbb --- /dev/null +++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/ProductReviews.php @@ -0,0 +1,129 @@ +product_category = $fixtures->get_product_category( + array( + 'name' => 'Test Category 1', + ) + ); + + $this->products = array( + $fixtures->get_simple_product( + array( + 'name' => 'Test Product 1', + 'regular_price' => 10, + ) + ), + $fixtures->get_simple_product( + array( + 'name' => 'Test Product 2', + 'regular_price' => 100, + 'category_ids' => array( $this->product_category['term_id'] ), + ) + ), + ); + + $fixtures->add_product_review( $this->products[0]->get_id(), 5 ); + $fixtures->add_product_review( $this->products[1]->get_id(), 4 ); + } + + /** + * Test getting reviews. + */ + public function test_get_items() { + $response = rest_get_server()->dispatch( new \WP_REST_Request( 'GET', '/wc/store/v1/products/reviews' ) ); + $data = $response->get_data(); + + // Assert correct response format. + $this->assertSame( 200, $response->get_status(), 'Unexpected status code.' ); + $this->assertSame( 2, count( $data ), 'Unexpected item count.' ); + + // Assert response items contain the correct properties. + $this->assertArrayHasKey( 'id', $data[0] ); + $this->assertArrayHasKey( 'date_created', $data[0] ); + $this->assertArrayHasKey( 'formatted_date_created', $data[0] ); + $this->assertArrayHasKey( 'date_created_gmt', $data[0] ); + $this->assertArrayHasKey( 'product_id', $data[0] ); + $this->assertArrayHasKey( 'product_name', $data[0] ); + $this->assertArrayHasKey( 'product_permalink', $data[0] ); + $this->assertArrayHasKey( 'product_image', $data[0] ); + $this->assertArrayHasKey( 'product_permalink', $data[0] ); + $this->assertArrayHasKey( 'reviewer', $data[0] ); + $this->assertArrayHasKey( 'review', $data[0] ); + $this->assertArrayHasKey( 'rating', $data[0] ); + $this->assertArrayHasKey( 'verified', $data[0] ); + $this->assertArrayHasKey( 'reviewer_avatar_urls', $data[0] ); + + // Assert response items contain the correct review data. + $this->assertSame( 'Test Product 2', $data[0]['product_name'] ); + $this->assertSame( 4, $data[0]['rating'] ); + $this->assertSame( 'Test Product 1', $data[1]['product_name'] ); + $this->assertSame( 5, $data[1]['rating'] ); + } + + /** + * Test getting reviews with specific order and per_page parameters. + */ + public function test_get_items_with_order_params() { + $request = new \WP_REST_Request( 'GET', '/wc/store/v1/products/reviews' ); + $request->set_param( 'per_page', 1 ); + $request->set_param( 'orderby', 'rating' ); + $request->set_param( 'order', 'desc' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertSame( 200, $response->get_status(), 'Unexpected status code.' ); + $this->assertCount( 1, $data, 'Unexpected item count.' ); + $this->assertSame( 5, $data[0]['rating'] ); + } + + /** + * Test getting reviews from a specific product. + */ + public function test_get_items_with_product_id_param() { + $request = new \WP_REST_Request( 'GET', '/wc/store/v1/products/reviews' ); + $request->set_param( 'product_id', (string) $this->products[0]->get_id() ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertSame( 200, $response->get_status(), 'Unexpected status code.' ); + $this->assertCount( 1, $data, 'Unexpected item count.' ); + $this->assertSame( 5, $data[0]['rating'] ); + } + + /** + * Test getting reviews from a specific category. + */ + public function test_get_items_with_category_id_param() { + $request = new \WP_REST_Request( 'GET', '/wc/store/v1/products/reviews' ); + $request->set_param( 'category_id', (string) $this->product_category['term_id'] ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertSame( 200, $response->get_status(), 'Unexpected status code.' ); + $this->assertCount( 1, $data, 'Unexpected item count.' ); + $this->assertSame( 4, $data[0]['rating'] ); + } +} From 1bf6b6e44a278427953619b291f2139acc1aaaf0 Mon Sep 17 00:00:00 2001 From: piinthecloud Date: Thu, 22 Aug 2024 14:25:57 +0200 Subject: [PATCH 075/185] fix lint rule (#50843) * fix lint rule * add manifest * add changelog --- docs/.markdownlint.json | 2 +- docs/docs-manifest.json | 8 ++++---- docs/extension-development/data-storage.md | 6 ++++++ docs/product-editor-development/README.md | 2 +- plugins/woocommerce/changelog/update-contribution-docs | 4 ++++ 5 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 plugins/woocommerce/changelog/update-contribution-docs diff --git a/docs/.markdownlint.json b/docs/.markdownlint.json index 6728d0fd76a..3297523f014 100644 --- a/docs/.markdownlint.json +++ b/docs/.markdownlint.json @@ -3,7 +3,7 @@ "MD003": { "style": "atx" }, "MD007": { "indent": 4 }, "MD013": { "line_length": 9999 }, - "MD024": { "allow_different_nesting": true }, + "MD024": { "siblings_only": true }, "MD033": { "allowed_elements": ["video"] }, "MD035": false, "MD041": false, diff --git a/docs/docs-manifest.json b/docs/docs-manifest.json index 00c65ffeb77..9537ea57ba4 100644 --- a/docs/docs-manifest.json +++ b/docs/docs-manifest.json @@ -761,7 +761,7 @@ "menu_title": "Data storage", "tags": "reference", "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/data-storage.md", - "hash": "ea827670b3a888f69cb50bc78dc10827c802abb135a5846f31cfa55e882f7faa", + "hash": "1ea2fabf927f9ced2fee89f930e9195c7df4d98ceb3d847436337376578802a3", "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/data-storage.md", "id": "b3e0b17ca74596e858c26887c1e4c8ee6c8f6102" }, @@ -1059,7 +1059,7 @@ "categories": [] }, { - "content": "\nDiscover how to customize the WooCommerce product editor, from extending product data to adding unique functionalities.\n\nThis handbook is a guide for extension developers looking to add support for the new product editor in their extensions. The product editor uses [Gutenberg's Block Editor](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor), which is going to help WooCommerce evolve alongside the WordPress ecosystem.", + "content": "\nDiscover how to customize the WooCommerce product editor, from extending product data to adding unique functionalities.\n\nThis handbook is a guide for extension developers looking to add support for the new product editor in their extensions. The product editor uses [Gutenberg's Block Editor](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor), which is going to help WooCommerce evolve alongside the WordPress ecosystem.\n", "category_slug": "product-editor", "category_title": "Product Editor", "posts": [ @@ -1378,7 +1378,7 @@ { "post_title": "Template structure & Overriding templates via a theme", "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/theme-development/template-structure.md", - "hash": "c0e346e7e21682bd645998f0607efe18f9f63601f53f4a53ab43248eefcab2d1", + "hash": "ff781eff7998ea93723f644bddd4f6da6f73c635bcfc3cd46950f03a8b83b26c", "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/theme-development/template-structure.md", "id": "34bfebec9fc45e680976814928a7b8a1778af14e" }, @@ -1731,5 +1731,5 @@ "categories": [] } ], - "hash": "95e835afe855d5a898bfc31337d2a42b582794d5e1aaacb9b4a98cfc97748e05" + "hash": "b6fab4eae1266824ee3e876c8fa5fd0342f59b4a0e5978f1460afc67d82e6d94" } \ No newline at end of file diff --git a/docs/extension-development/data-storage.md b/docs/extension-development/data-storage.md index e6c05919192..8eb1350fa0b 100644 --- a/docs/extension-development/data-storage.md +++ b/docs/extension-development/data-storage.md @@ -7,21 +7,27 @@ tags: reference When developing for WordPress and WooCommerce, it's important to consider the nature and permanence of your data. This will help you decide the best way to store it. Here's a quick primer: ## Transients + If the data may not always be present (i.e., it expires), use a [transient](https://developer.wordpress.org/apis/handbook/transients/). Transients are a simple and standardized way of storing cached data in the database temporarily by giving it a custom name and a timeframe after which it will expire and be deleted. ## WP Cache + If the data is persistent but not always present, consider using the [WP Cache](https://developer.wordpress.org/reference/classes/wp_object_cache/). The WP Cache functions allow you to cache data that is computationally expensive to regenerate, such as complex query results. ## wp_options Table + If the data is persistent and always present, consider the [wp_options table](https://developer.wordpress.org/apis/handbook/options/). The Options API is a simple and standardized way of storing data in the wp_options table in the WordPress database. ## Post Types + If the data type is an entity with n units, consider a [post type](https://developer.wordpress.org/post_type/). Post types are "types" of content that are stored in the same way, but are easy to distinguish in the code and UI. ## Taxonomies + If the data is a means of sorting/categorizing an entity, consider a [taxonomy](https://developer.wordpress.org/taxonomy/). Taxonomies are a way of grouping things together. ## Logging + Logs should be written to a file using the [WC_Logger](https://woocommerce.com/wc-apidocs/class-WC_Logger.html) class. This is a simple and standardized way of recording events and errors for debugging purposes. Remember, the best method of data storage depends on the nature of the data and how it will be used in your application. diff --git a/docs/product-editor-development/README.md b/docs/product-editor-development/README.md index 1d717ad5322..db9e8f5d4bd 100644 --- a/docs/product-editor-development/README.md +++ b/docs/product-editor-development/README.md @@ -6,4 +6,4 @@ post_title: Product Editor Discover how to customize the WooCommerce product editor, from extending product data to adding unique functionalities. -This handbook is a guide for extension developers looking to add support for the new product editor in their extensions. The product editor uses [Gutenberg's Block Editor](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor), which is going to help WooCommerce evolve alongside the WordPress ecosystem. \ No newline at end of file +This handbook is a guide for extension developers looking to add support for the new product editor in their extensions. The product editor uses [Gutenberg's Block Editor](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor), which is going to help WooCommerce evolve alongside the WordPress ecosystem. diff --git a/plugins/woocommerce/changelog/update-contribution-docs b/plugins/woocommerce/changelog/update-contribution-docs new file mode 100644 index 00000000000..0712915d3bc --- /dev/null +++ b/plugins/woocommerce/changelog/update-contribution-docs @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +fix small lint errors and fix lint rule to make doc contribution easier From 7ba0fb4fde5cb71562fdb16149010ab822c16b81 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:47:25 -0300 Subject: [PATCH 076/185] Prep trunk for 9.4 cycle (#50859) Prep trunk for 9.4 cycle with version bump to 9.4.0-dev Co-authored-by: WooCommerce Bot --- plugins/woocommerce/composer.json | 2 +- plugins/woocommerce/includes/class-woocommerce.php | 2 +- plugins/woocommerce/package.json | 2 +- plugins/woocommerce/readme.txt | 2 +- plugins/woocommerce/woocommerce.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce/composer.json b/plugins/woocommerce/composer.json index 52052c43651..b51f7e3c195 100644 --- a/plugins/woocommerce/composer.json +++ b/plugins/woocommerce/composer.json @@ -2,7 +2,7 @@ "name": "woocommerce/woocommerce", "description": "An eCommerce toolkit that helps you sell anything. Beautifully.", "homepage": "https://woocommerce.com/", - "version": "9.3.0", + "version": "9.4.0", "type": "wordpress-plugin", "license": "GPL-3.0-or-later", "prefer-stable": true, diff --git a/plugins/woocommerce/includes/class-woocommerce.php b/plugins/woocommerce/includes/class-woocommerce.php index b2ecf887b0f..41104fcbd65 100644 --- a/plugins/woocommerce/includes/class-woocommerce.php +++ b/plugins/woocommerce/includes/class-woocommerce.php @@ -46,7 +46,7 @@ final class WooCommerce { * * @var string */ - public $version = '9.3.0'; + public $version = '9.4.0'; /** * WooCommerce Schema version. diff --git a/plugins/woocommerce/package.json b/plugins/woocommerce/package.json index 3e985a6f783..7ed07ba6aba 100644 --- a/plugins/woocommerce/package.json +++ b/plugins/woocommerce/package.json @@ -2,7 +2,7 @@ "name": "@woocommerce/plugin-woocommerce", "private": true, "title": "WooCommerce", - "version": "9.3.0", + "version": "9.4.0", "homepage": "https://woocommerce.com/", "repository": { "type": "git", diff --git a/plugins/woocommerce/readme.txt b/plugins/woocommerce/readme.txt index bbc9093ada2..04146902c1c 100644 --- a/plugins/woocommerce/readme.txt +++ b/plugins/woocommerce/readme.txt @@ -169,6 +169,6 @@ WooCommerce comes with some sample data you can use to see how products look; im == Changelog == -= 9.3.0 2024-XX-XX = += 9.4.0 2024-XX-XX = [See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/changelog.txt). diff --git a/plugins/woocommerce/woocommerce.php b/plugins/woocommerce/woocommerce.php index 391f2f454d9..b03085e7ac6 100644 --- a/plugins/woocommerce/woocommerce.php +++ b/plugins/woocommerce/woocommerce.php @@ -3,7 +3,7 @@ * Plugin Name: WooCommerce * Plugin URI: https://woocommerce.com/ * Description: An ecommerce toolkit that helps you sell anything. Beautifully. - * Version: 9.3.0-dev + * Version: 9.4.0-dev * Author: Automattic * Author URI: https://woocommerce.com * Text Domain: woocommerce From 320c165cb8f23aaafd48f4f3b1007d36b6b60fc0 Mon Sep 17 00:00:00 2001 From: Roy Ho Date: Thu, 22 Aug 2024 06:32:03 -0700 Subject: [PATCH 077/185] Add additional size units to product image element (#50770) * Add additional size units to product image element * Add changefile(s) from automation for the following project(s): woocommerce-blocks --------- Co-authored-by: github-actions --- .../image/image-size-settings.tsx | 41 +++++++++++++------ .../50770-image-add-additional-size-units | 4 ++ 2 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 plugins/woocommerce/changelog/50770-image-add-additional-size-units diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/image/image-size-settings.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/image/image-size-settings.tsx index fc4839332fc..5b9f3620d58 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/image/image-size-settings.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/image/image-size-settings.tsx @@ -43,6 +43,33 @@ const scaleHelp: Record< string, string > = { ), }; +const sizeUnits: { value: string; label: string }[] = [ + { + value: 'px', + label: 'px', + }, + { + value: 'em', + label: 'em', + }, + { + value: 'rem', + label: 'rem', + }, + { + value: '%', + label: '%', + }, + { + value: 'vw', + label: 'vw', + }, + { + value: 'vh', + label: 'vh', + }, +]; + export const ImageSizeSettings = ( { scale, width, @@ -60,12 +87,7 @@ export const ImageSizeSettings = ( { setAttributes( { height: value } ); } } value={ height } - units={ [ - { - value: 'px', - label: 'px', - }, - ] } + units={ sizeUnits } /> { height && ( Date: Thu, 22 Aug 2024 10:55:20 -0400 Subject: [PATCH 078/185] Blocks E2E: Move the inspector controls e2e tests from product collection file to its own file (#50849) * Move the inspector controls e2e tests from product collection file to its own file * Add changelog file --- .../inspector-controls.block_theme.spec.ts | 639 ++++++++++++++++++ .../product-collection.block_theme.spec.ts | 617 ----------------- .../changelog/test-50444-inspector-control | 4 + 3 files changed, 643 insertions(+), 617 deletions(-) create mode 100644 plugins/woocommerce-blocks/tests/e2e/tests/product-collection/inspector-controls/inspector-controls.block_theme.spec.ts create mode 100644 plugins/woocommerce/changelog/test-50444-inspector-control diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/inspector-controls/inspector-controls.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/inspector-controls/inspector-controls.block_theme.spec.ts new file mode 100644 index 00000000000..b1a696e81ad --- /dev/null +++ b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/inspector-controls/inspector-controls.block_theme.spec.ts @@ -0,0 +1,639 @@ +/** + * External dependencies + */ +import { test as base, expect } from '@woocommerce/e2e-utils'; + +/** + * Internal dependencies + */ +import ProductCollectionPage, { SELECTORS } from '../product-collection.page'; + +const test = base.extend< { pageObject: ProductCollectionPage } >( { + pageObject: async ( { page, admin, editor }, use ) => { + const pageObject = new ProductCollectionPage( { + page, + admin, + editor, + } ); + await use( pageObject ); + }, +} ); + +test.describe( 'Product Collection', () => { + test.describe( 'Inspector Controls', () => { + test( 'Reflects the correct number of columns according to sidebar settings', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await pageObject.setNumberOfColumns( 2 ); + await expect( pageObject.productTemplate ).toHaveClass( + /columns-2/ + ); + + await pageObject.setNumberOfColumns( 4 ); + await expect( pageObject.productTemplate ).toHaveClass( + /columns-4/ + ); + + await pageObject.publishAndGoToFrontend(); + + await expect( pageObject.productTemplate ).toHaveClass( + /columns-4/ + ); + } ); + + test( 'Order By - sort products by title in descending order correctly', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + const sortedTitles = [ + 'WordPress Pennant', + 'V-Neck T-Shirt', + 'T-Shirt with Logo', + 'T-Shirt', + /Sunglasses/, // In the frontend it's "Protected: Sunglasses" + 'Single', + 'Polo', + 'Long Sleeve Tee', + 'Logo Collection', + ]; + + await pageObject.setOrderBy( 'title/desc' ); + await expect( pageObject.productTitles ).toHaveText( sortedTitles ); + + await pageObject.publishAndGoToFrontend(); + await expect( pageObject.productTitles ).toHaveText( sortedTitles ); + } ); + + // Products can be filtered based on 'on sale' status. + test( 'Products can be filtered based on "on sale" status', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + let allProducts = pageObject.products; + let saleProducts = pageObject.products.filter( { + hasText: 'Product on sale', + } ); + + await expect( allProducts ).toHaveCount( 9 ); + await expect( saleProducts ).toHaveCount( 6 ); + + await pageObject.setShowOnlyProductsOnSale( { + onSale: true, + } ); + + await expect( allProducts ).toHaveCount( 6 ); + await expect( saleProducts ).toHaveCount( 6 ); + + await pageObject.publishAndGoToFrontend(); + await pageObject.refreshLocators( 'frontend' ); + allProducts = pageObject.products; + saleProducts = pageObject.products.filter( { + hasText: 'Product on sale', + } ); + + await expect( allProducts ).toHaveCount( 6 ); + await expect( saleProducts ).toHaveCount( 6 ); + } ); + + test( 'Products can be filtered based on selection in handpicked products option', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await pageObject.addFilter( 'Show Hand-picked Products' ); + + const filterName = 'Hand-picked Products'; + await pageObject.setFilterComboboxValue( filterName, [ 'Album' ] ); + await expect( pageObject.products ).toHaveCount( 1 ); + + const productNames = [ 'Album', 'Cap' ]; + await pageObject.setFilterComboboxValue( filterName, productNames ); + await expect( pageObject.products ).toHaveCount( 2 ); + await expect( pageObject.productTitles ).toHaveText( productNames ); + + await pageObject.publishAndGoToFrontend(); + await expect( pageObject.products ).toHaveCount( 2 ); + await expect( pageObject.productTitles ).toHaveText( productNames ); + } ); + + test( 'Products can be filtered based on keyword.', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await pageObject.addFilter( 'Keyword' ); + + await pageObject.setKeyword( 'Album' ); + await expect( pageObject.productTitles ).toHaveText( [ 'Album' ] ); + + await pageObject.setKeyword( 'Cap' ); + await expect( pageObject.productTitles ).toHaveText( [ 'Cap' ] ); + + await pageObject.publishAndGoToFrontend(); + await expect( pageObject.productTitles ).toHaveText( [ 'Cap' ] ); + } ); + + test( 'Products can be filtered based on category.', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + const filterName = 'Product categories'; + await pageObject.addFilter( 'Show product categories' ); + await pageObject.setFilterComboboxValue( filterName, [ + 'Clothing', + ] ); + await expect( pageObject.productTitles ).toHaveText( [ + 'Logo Collection', + ] ); + + await pageObject.setFilterComboboxValue( filterName, [ + 'Accessories', + ] ); + const accessoriesProductNames = [ + 'Beanie', + 'Beanie with Logo', + 'Belt', + 'Cap', + 'Sunglasses', + ]; + await expect( pageObject.productTitles ).toHaveText( + accessoriesProductNames + ); + + await pageObject.publishAndGoToFrontend(); + + const frontendAccessoriesProductNames = [ + 'Beanie', + 'Beanie with Logo', + 'Belt', + 'Cap', + 'Protected: Sunglasses', + ]; + await expect( pageObject.productTitles ).toHaveText( + frontendAccessoriesProductNames + ); + } ); + + test( 'Products can be filtered based on tags.', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + const filterName = 'Product tags'; + await pageObject.addFilter( 'Show product tags' ); + await pageObject.setFilterComboboxValue( filterName, [ + 'Recommended', + ] ); + await expect( pageObject.productTitles ).toHaveText( [ + 'Beanie', + 'Hoodie', + ] ); + + await pageObject.publishAndGoToFrontend(); + await expect( pageObject.productTitles ).toHaveText( [ + 'Beanie', + 'Hoodie', + ] ); + } ); + + test( 'Products can be filtered based on product attributes like color, size etc.', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await pageObject.addFilter( 'Show Product Attributes' ); + await pageObject.setProductAttribute( 'Color', 'Green' ); + + await expect( pageObject.products ).toHaveCount( 3 ); + + await pageObject.setProductAttribute( 'Size', 'Large' ); + + await expect( pageObject.products ).toHaveCount( 1 ); + + await pageObject.publishAndGoToFrontend(); + + await expect( pageObject.products ).toHaveCount( 1 ); + } ); + + test( 'Products can be filtered based on stock status (in stock, out of stock, or backorder).', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await pageObject.setFilterComboboxValue( 'Stock status', [ + 'Out of stock', + ] ); + + await expect( pageObject.productTitles ).toHaveText( [ + 'T-Shirt with Logo', + ] ); + + await pageObject.publishAndGoToFrontend(); + + await expect( pageObject.productTitles ).toHaveText( [ + 'T-Shirt with Logo', + ] ); + } ); + + test( 'Products can be filtered based on featured status.', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await pageObject.addFilter( 'Featured' ); + await pageObject.setShowOnlyFeaturedProducts( { + featured: true, + } ); + + // In test data we have only 4 featured products. + await expect( pageObject.products ).toHaveCount( 4 ); + + await pageObject.publishAndGoToFrontend(); + + await expect( pageObject.products ).toHaveCount( 4 ); + } ); + + test( 'Products can be filtered based on created date.', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await pageObject.addFilter( 'Created' ); + await pageObject.setCreatedFilter( { + operator: 'within', + range: 'last3months', + } ); + + // Products are created with the fixed publish date back in 2019 + // so there's no products published in last 3 months. + await expect( pageObject.products ).toHaveCount( 0 ); + + await pageObject.setCreatedFilter( { + operator: 'before', + range: 'last3months', + } ); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await pageObject.publishAndGoToFrontend(); + + await expect( pageObject.products ).toHaveCount( 9 ); + } ); + + test( 'Products can be filtered based on price range.', async ( { + pageObject, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await pageObject.addFilter( 'Price Range' ); + await pageObject.setPriceRange( { + min: '18.33', + } ); + + await expect( pageObject.products ).toHaveCount( 7 ); + + await pageObject.setPriceRange( { + min: '15.28', + max: '17.21', + } ); + + await expect( pageObject.products ).toHaveCount( 1 ); + + await pageObject.setPriceRange( { + max: '17.29', + } ); + + await expect( pageObject.products ).toHaveCount( 4 ); + + await pageObject.publishAndGoToFrontend(); + + await expect( pageObject.products ).toHaveCount( 4 ); + } ); + + // See https://github.com/woocommerce/woocommerce/pull/49917 + test( 'Price range is inclusive in both editor and frontend.', async ( { + page, + pageObject, + editor, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await pageObject.addFilter( 'Price Range' ); + await pageObject.setPriceRange( { + min: '45', + max: '55', + } ); + + // Wait for the products to be filtered. + await expect( pageObject.products ).not.toHaveCount( 9 ); + + await expect( + pageObject.products.filter( { hasText: '$45.00' } ) + ).not.toHaveCount( 0 ); + await expect( + pageObject.products.filter( { hasText: '$55.00' } ) + ).not.toHaveCount( 0 ); + + // Reset the price range. + await pageObject.setPriceRange( { + min: '0', + max: '0', + } ); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await editor.insertBlock( { + name: 'woocommerce/filter-wrapper', + attributes: { filterType: 'price-filter' }, + } ); + + await pageObject.publishAndGoToFrontend(); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await page + .getByRole( 'textbox', { + name: 'Filter products by minimum', + } ) + .dblclick(); + await page.keyboard.type( '45' ); + + await page + .getByRole( 'textbox', { + name: 'Filter products by maximum', + } ) + .dblclick(); + await page.keyboard.type( '55' ); + + await page.keyboard.press( 'Tab' ); + + // Wait for the products to be filtered. + await expect( pageObject.products ).not.toHaveCount( 9 ); + + await expect( + pageObject.products.filter( { hasText: '$45.00' } ) + ).not.toHaveCount( 0 ); + await expect( + pageObject.products.filter( { hasText: '$55.00' } ) + ).not.toHaveCount( 0 ); + } ); + + test.describe( '"Use page context" control', () => { + test( 'should be visible on posts', async ( { pageObject } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await expect( + pageObject + .locateSidebarSettings() + .locator( SELECTORS.usePageContextControl ) + ).toBeVisible(); + } ); + + [ + 'woocommerce/woocommerce//archive-product', + 'woocommerce/woocommerce//taxonomy-product_cat', + 'woocommerce/woocommerce//taxonomy-product_tag', + 'woocommerce/woocommerce//taxonomy-product_attribute', + 'woocommerce/woocommerce//product-search-results', + ].forEach( ( slug ) => { + test( `should be visible in archive template: ${ slug }`, async ( { + pageObject, + editor, + } ) => { + await pageObject.goToEditorTemplate( slug ); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInTemplate(); + await pageObject.focusProductCollection(); + await editor.openDocumentSettingsSidebar(); + + await expect( + pageObject + .locateSidebarSettings() + .locator( SELECTORS.usePageContextControl ) + ).toBeVisible(); + } ); + } ); + + [ + 'woocommerce/woocommerce//single-product', + 'twentytwentyfour//home', + 'twentytwentyfour//index', + ].forEach( ( slug ) => { + test( `should be visible in non-archive template: ${ slug }`, async ( { + pageObject, + editor, + } ) => { + await pageObject.goToEditorTemplate( slug ); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInTemplate(); + await pageObject.focusProductCollection(); + await editor.openDocumentSettingsSidebar(); + + await expect( + pageObject + .locateSidebarSettings() + .locator( SELECTORS.usePageContextControl ) + ).toBeVisible(); + } ); + } ); + + test( 'should work as expected in Product Catalog template', async ( { + pageObject, + editor, + } ) => { + await pageObject.goToEditorTemplate(); + await pageObject.focusProductCollection(); + await editor.openDocumentSettingsSidebar(); + + const sidebarSettings = pageObject.locateSidebarSettings(); + + // Inherit query from template should be visible & enabled by default + await expect( + sidebarSettings.locator( SELECTORS.usePageContextControl ) + ).toBeVisible(); + await expect( + sidebarSettings.locator( + `${ SELECTORS.usePageContextControl } input` + ) + ).toBeChecked(); + + // "On sale control" should be hidden when inherit query from template is enabled + await expect( + sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) + ).toBeHidden(); + + // "On sale control" should be visible when inherit query from template is disabled + await pageObject.setInheritQueryFromTemplate( false ); + await expect( + sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) + ).toBeVisible(); + + // "On sale control" should retain its state when inherit query from template is enabled again + await pageObject.setShowOnlyProductsOnSale( { + onSale: true, + isLocatorsRefreshNeeded: false, + } ); + await expect( + sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) + ).toBeChecked(); + await pageObject.setInheritQueryFromTemplate( true ); + await expect( + sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) + ).toBeHidden(); + await pageObject.setInheritQueryFromTemplate( false ); + await expect( + sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) + ).toBeVisible(); + await expect( + sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) + ).toBeChecked(); + } ); + + test( 'is enabled by default unless already enabled elsewhere', async ( { + pageObject, + editor, + } ) => { + const productCollection = editor.canvas.getByLabel( + 'Block: Product Collection', + { exact: true } + ); + const usePageContextToggle = pageObject + .locateSidebarSettings() + .locator( SELECTORS.usePageContextControl ) + .locator( 'input' ); + + // First Product Catalog + // Option should be visible & ENABLED by default + await pageObject.goToEditorTemplate(); + await editor.selectBlocks( productCollection.first() ); + await editor.openDocumentSettingsSidebar(); + + await expect( usePageContextToggle ).toBeChecked(); + + // Second Product Catalog + // Option should be visible & DISABLED by default + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInTemplate( 'productCatalog' ); + await editor.selectBlocks( productCollection.last() ); + + await expect( usePageContextToggle ).not.toBeChecked(); + + // Disable the option in the first Product Catalog + await editor.selectBlocks( productCollection.first() ); + await usePageContextToggle.click(); + + // Third Product Catalog + // Option should be visible & ENABLED by default + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInTemplate( 'productCatalog' ); + await editor.selectBlocks( productCollection.last() ); + + await expect( usePageContextToggle ).toBeChecked(); + } ); + + test( 'allows filtering in non-archive context', async ( { + pageObject, + editor, + page, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( 'productCatalog' ); + + await expect( pageObject.products ).toHaveCount( 18 ); + + await page.getByLabel( 'Toggle block inserter' ).click(); + await page.getByRole( 'tab', { name: 'Patterns' } ).click(); + await page + .getByPlaceholder( 'Search' ) + .fill( 'product filters' ); + await page.getByLabel( 'Product Filters' ).click(); + + const postId = await editor.publishPost(); + await page.goto( `/?p=${ postId }` ); + + const productCollection = page.locator( + '.wp-block-woocommerce-product-collection' + ); + + await expect( + productCollection.first().locator( SELECTORS.product ) + ).toHaveCount( 9 ); + await expect( + productCollection.last().locator( SELECTORS.product ) + ).toHaveCount( 9 ); + + await page + .getByRole( 'textbox', { + name: 'Filter products by maximum', + } ) + .dblclick(); + await page.keyboard.type( '10' ); + await page.keyboard.press( 'Tab' ); + + await expect( + productCollection.first().locator( SELECTORS.product ) + ).toHaveCount( 1 ); + await expect( + productCollection.last().locator( SELECTORS.product ) + ).toHaveCount( 9 ); + } ); + + test( 'correctly combines editor and front-end filters', async ( { + pageObject, + editor, + page, + } ) => { + await pageObject.createNewPostAndInsertBlock(); + + await expect( pageObject.products ).toHaveCount( 9 ); + + await pageObject.addFilter( 'Show product categories' ); + await pageObject.setFilterComboboxValue( 'Product categories', [ + 'Music', + ] ); + + await page.getByLabel( 'Toggle block inserter' ).click(); + await page.getByRole( 'tab', { name: 'Patterns' } ).click(); + await page + .getByPlaceholder( 'Search' ) + .fill( 'product filters' ); + await page.getByLabel( 'Product Filters' ).click(); + + await expect( pageObject.products ).toHaveCount( 2 ); + + const postId = await editor.publishPost(); + await page.goto( `/?p=${ postId }` ); + await pageObject.refreshLocators( 'frontend' ); + + await expect( pageObject.products ).toHaveCount( 2 ); + + await page + .getByRole( 'textbox', { + name: 'Filter products by maximum', + } ) + .dblclick(); + await page.keyboard.type( '5' ); + await page.keyboard.press( 'Tab' ); + + await expect( pageObject.products ).toHaveCount( 1 ); + } ); + } ); + } ); +} ); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts index dd48320f303..026402747e9 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts @@ -165,623 +165,6 @@ test.describe( 'Product Collection', () => { } ); } ); - test.describe( 'Inspector Controls', () => { - test( 'Reflects the correct number of columns according to sidebar settings', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await pageObject.setNumberOfColumns( 2 ); - await expect( pageObject.productTemplate ).toHaveClass( - /columns-2/ - ); - - await pageObject.setNumberOfColumns( 4 ); - await expect( pageObject.productTemplate ).toHaveClass( - /columns-4/ - ); - - await pageObject.publishAndGoToFrontend(); - - await expect( pageObject.productTemplate ).toHaveClass( - /columns-4/ - ); - } ); - - test( 'Order By - sort products by title in descending order correctly', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - const sortedTitles = [ - 'WordPress Pennant', - 'V-Neck T-Shirt', - 'T-Shirt with Logo', - 'T-Shirt', - /Sunglasses/, // In the frontend it's "Protected: Sunglasses" - 'Single', - 'Polo', - 'Long Sleeve Tee', - 'Logo Collection', - ]; - - await pageObject.setOrderBy( 'title/desc' ); - await expect( pageObject.productTitles ).toHaveText( sortedTitles ); - - await pageObject.publishAndGoToFrontend(); - await expect( pageObject.productTitles ).toHaveText( sortedTitles ); - } ); - - // Products can be filtered based on 'on sale' status. - test( 'Products can be filtered based on "on sale" status', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - let allProducts = pageObject.products; - let saleProducts = pageObject.products.filter( { - hasText: 'Product on sale', - } ); - - await expect( allProducts ).toHaveCount( 9 ); - await expect( saleProducts ).toHaveCount( 6 ); - - await pageObject.setShowOnlyProductsOnSale( { - onSale: true, - } ); - - await expect( allProducts ).toHaveCount( 6 ); - await expect( saleProducts ).toHaveCount( 6 ); - - await pageObject.publishAndGoToFrontend(); - await pageObject.refreshLocators( 'frontend' ); - allProducts = pageObject.products; - saleProducts = pageObject.products.filter( { - hasText: 'Product on sale', - } ); - - await expect( allProducts ).toHaveCount( 6 ); - await expect( saleProducts ).toHaveCount( 6 ); - } ); - - test( 'Products can be filtered based on selection in handpicked products option', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await pageObject.addFilter( 'Show Hand-picked Products' ); - - const filterName = 'Hand-picked Products'; - await pageObject.setFilterComboboxValue( filterName, [ 'Album' ] ); - await expect( pageObject.products ).toHaveCount( 1 ); - - const productNames = [ 'Album', 'Cap' ]; - await pageObject.setFilterComboboxValue( filterName, productNames ); - await expect( pageObject.products ).toHaveCount( 2 ); - await expect( pageObject.productTitles ).toHaveText( productNames ); - - await pageObject.publishAndGoToFrontend(); - await expect( pageObject.products ).toHaveCount( 2 ); - await expect( pageObject.productTitles ).toHaveText( productNames ); - } ); - - test( 'Products can be filtered based on keyword.', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await pageObject.addFilter( 'Keyword' ); - - await pageObject.setKeyword( 'Album' ); - await expect( pageObject.productTitles ).toHaveText( [ 'Album' ] ); - - await pageObject.setKeyword( 'Cap' ); - await expect( pageObject.productTitles ).toHaveText( [ 'Cap' ] ); - - await pageObject.publishAndGoToFrontend(); - await expect( pageObject.productTitles ).toHaveText( [ 'Cap' ] ); - } ); - - test( 'Products can be filtered based on category.', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - const filterName = 'Product categories'; - await pageObject.addFilter( 'Show product categories' ); - await pageObject.setFilterComboboxValue( filterName, [ - 'Clothing', - ] ); - await expect( pageObject.productTitles ).toHaveText( [ - 'Logo Collection', - ] ); - - await pageObject.setFilterComboboxValue( filterName, [ - 'Accessories', - ] ); - const accessoriesProductNames = [ - 'Beanie', - 'Beanie with Logo', - 'Belt', - 'Cap', - 'Sunglasses', - ]; - await expect( pageObject.productTitles ).toHaveText( - accessoriesProductNames - ); - - await pageObject.publishAndGoToFrontend(); - - const frontendAccessoriesProductNames = [ - 'Beanie', - 'Beanie with Logo', - 'Belt', - 'Cap', - 'Protected: Sunglasses', - ]; - await expect( pageObject.productTitles ).toHaveText( - frontendAccessoriesProductNames - ); - } ); - - test( 'Products can be filtered based on tags.', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - const filterName = 'Product tags'; - await pageObject.addFilter( 'Show product tags' ); - await pageObject.setFilterComboboxValue( filterName, [ - 'Recommended', - ] ); - await expect( pageObject.productTitles ).toHaveText( [ - 'Beanie', - 'Hoodie', - ] ); - - await pageObject.publishAndGoToFrontend(); - await expect( pageObject.productTitles ).toHaveText( [ - 'Beanie', - 'Hoodie', - ] ); - } ); - - test( 'Products can be filtered based on product attributes like color, size etc.', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await pageObject.addFilter( 'Show Product Attributes' ); - await pageObject.setProductAttribute( 'Color', 'Green' ); - - await expect( pageObject.products ).toHaveCount( 3 ); - - await pageObject.setProductAttribute( 'Size', 'Large' ); - - await expect( pageObject.products ).toHaveCount( 1 ); - - await pageObject.publishAndGoToFrontend(); - - await expect( pageObject.products ).toHaveCount( 1 ); - } ); - - test( 'Products can be filtered based on stock status (in stock, out of stock, or backorder).', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await pageObject.setFilterComboboxValue( 'Stock status', [ - 'Out of stock', - ] ); - - await expect( pageObject.productTitles ).toHaveText( [ - 'T-Shirt with Logo', - ] ); - - await pageObject.publishAndGoToFrontend(); - - await expect( pageObject.productTitles ).toHaveText( [ - 'T-Shirt with Logo', - ] ); - } ); - - test( 'Products can be filtered based on featured status.', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await pageObject.addFilter( 'Featured' ); - await pageObject.setShowOnlyFeaturedProducts( { - featured: true, - } ); - - // In test data we have only 4 featured products. - await expect( pageObject.products ).toHaveCount( 4 ); - - await pageObject.publishAndGoToFrontend(); - - await expect( pageObject.products ).toHaveCount( 4 ); - } ); - - test( 'Products can be filtered based on created date.', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await pageObject.addFilter( 'Created' ); - await pageObject.setCreatedFilter( { - operator: 'within', - range: 'last3months', - } ); - - // Products are created with the fixed publish date back in 2019 - // so there's no products published in last 3 months. - await expect( pageObject.products ).toHaveCount( 0 ); - - await pageObject.setCreatedFilter( { - operator: 'before', - range: 'last3months', - } ); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await pageObject.publishAndGoToFrontend(); - - await expect( pageObject.products ).toHaveCount( 9 ); - } ); - - test( 'Products can be filtered based on price range.', async ( { - pageObject, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await pageObject.addFilter( 'Price Range' ); - await pageObject.setPriceRange( { - min: '18.33', - } ); - - await expect( pageObject.products ).toHaveCount( 7 ); - - await pageObject.setPriceRange( { - min: '15.28', - max: '17.21', - } ); - - await expect( pageObject.products ).toHaveCount( 1 ); - - await pageObject.setPriceRange( { - max: '17.29', - } ); - - await expect( pageObject.products ).toHaveCount( 4 ); - - await pageObject.publishAndGoToFrontend(); - - await expect( pageObject.products ).toHaveCount( 4 ); - } ); - - // See https://github.com/woocommerce/woocommerce/pull/49917 - test( 'Price range is inclusive in both editor and frontend.', async ( { - page, - pageObject, - editor, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await pageObject.addFilter( 'Price Range' ); - await pageObject.setPriceRange( { - min: '45', - max: '55', - } ); - - // Wait for the products to be filtered. - await expect( pageObject.products ).not.toHaveCount( 9 ); - - await expect( - pageObject.products.filter( { hasText: '$45.00' } ) - ).not.toHaveCount( 0 ); - await expect( - pageObject.products.filter( { hasText: '$55.00' } ) - ).not.toHaveCount( 0 ); - - // Reset the price range. - await pageObject.setPriceRange( { - min: '0', - max: '0', - } ); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await editor.insertBlock( { - name: 'woocommerce/filter-wrapper', - attributes: { filterType: 'price-filter' }, - } ); - - await pageObject.publishAndGoToFrontend(); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await page - .getByRole( 'textbox', { - name: 'Filter products by minimum', - } ) - .dblclick(); - await page.keyboard.type( '45' ); - - await page - .getByRole( 'textbox', { - name: 'Filter products by maximum', - } ) - .dblclick(); - await page.keyboard.type( '55' ); - - await page.keyboard.press( 'Tab' ); - - // Wait for the products to be filtered. - await expect( pageObject.products ).not.toHaveCount( 9 ); - - await expect( - pageObject.products.filter( { hasText: '$45.00' } ) - ).not.toHaveCount( 0 ); - await expect( - pageObject.products.filter( { hasText: '$55.00' } ) - ).not.toHaveCount( 0 ); - } ); - - test.describe( '"Use page context" control', () => { - test( 'should be visible on posts', async ( { pageObject } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await expect( - pageObject - .locateSidebarSettings() - .locator( SELECTORS.usePageContextControl ) - ).toBeVisible(); - } ); - - [ - 'woocommerce/woocommerce//archive-product', - 'woocommerce/woocommerce//taxonomy-product_cat', - 'woocommerce/woocommerce//taxonomy-product_tag', - 'woocommerce/woocommerce//taxonomy-product_attribute', - 'woocommerce/woocommerce//product-search-results', - ].forEach( ( slug ) => { - test( `should be visible in archive template: ${ slug }`, async ( { - pageObject, - editor, - } ) => { - await pageObject.goToEditorTemplate( slug ); - await pageObject.insertProductCollection(); - await pageObject.chooseCollectionInTemplate(); - await pageObject.focusProductCollection(); - await editor.openDocumentSettingsSidebar(); - - await expect( - pageObject - .locateSidebarSettings() - .locator( SELECTORS.usePageContextControl ) - ).toBeVisible(); - } ); - } ); - - [ - 'woocommerce/woocommerce//single-product', - 'twentytwentyfour//home', - 'twentytwentyfour//index', - ].forEach( ( slug ) => { - test( `should be visible in non-archive template: ${ slug }`, async ( { - pageObject, - editor, - } ) => { - await pageObject.goToEditorTemplate( slug ); - await pageObject.insertProductCollection(); - await pageObject.chooseCollectionInTemplate(); - await pageObject.focusProductCollection(); - await editor.openDocumentSettingsSidebar(); - - await expect( - pageObject - .locateSidebarSettings() - .locator( SELECTORS.usePageContextControl ) - ).toBeVisible(); - } ); - } ); - - test( 'should work as expected in Product Catalog template', async ( { - pageObject, - editor, - } ) => { - await pageObject.goToEditorTemplate(); - await pageObject.focusProductCollection(); - await editor.openDocumentSettingsSidebar(); - - const sidebarSettings = pageObject.locateSidebarSettings(); - - // Inherit query from template should be visible & enabled by default - await expect( - sidebarSettings.locator( SELECTORS.usePageContextControl ) - ).toBeVisible(); - await expect( - sidebarSettings.locator( - `${ SELECTORS.usePageContextControl } input` - ) - ).toBeChecked(); - - // "On sale control" should be hidden when inherit query from template is enabled - await expect( - sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) - ).toBeHidden(); - - // "On sale control" should be visible when inherit query from template is disabled - await pageObject.setInheritQueryFromTemplate( false ); - await expect( - sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) - ).toBeVisible(); - - // "On sale control" should retain its state when inherit query from template is enabled again - await pageObject.setShowOnlyProductsOnSale( { - onSale: true, - isLocatorsRefreshNeeded: false, - } ); - await expect( - sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) - ).toBeChecked(); - await pageObject.setInheritQueryFromTemplate( true ); - await expect( - sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) - ).toBeHidden(); - await pageObject.setInheritQueryFromTemplate( false ); - await expect( - sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) - ).toBeVisible(); - await expect( - sidebarSettings.getByLabel( SELECTORS.onSaleControlLabel ) - ).toBeChecked(); - } ); - - test( 'is enabled by default unless already enabled elsewhere', async ( { - pageObject, - editor, - } ) => { - const productCollection = editor.canvas.getByLabel( - 'Block: Product Collection', - { exact: true } - ); - const usePageContextToggle = pageObject - .locateSidebarSettings() - .locator( SELECTORS.usePageContextControl ) - .locator( 'input' ); - - // First Product Catalog - // Option should be visible & ENABLED by default - await pageObject.goToEditorTemplate(); - await editor.selectBlocks( productCollection.first() ); - await editor.openDocumentSettingsSidebar(); - - await expect( usePageContextToggle ).toBeChecked(); - - // Second Product Catalog - // Option should be visible & DISABLED by default - await pageObject.insertProductCollection(); - await pageObject.chooseCollectionInTemplate( 'productCatalog' ); - await editor.selectBlocks( productCollection.last() ); - - await expect( usePageContextToggle ).not.toBeChecked(); - - // Disable the option in the first Product Catalog - await editor.selectBlocks( productCollection.first() ); - await usePageContextToggle.click(); - - // Third Product Catalog - // Option should be visible & ENABLED by default - await pageObject.insertProductCollection(); - await pageObject.chooseCollectionInTemplate( 'productCatalog' ); - await editor.selectBlocks( productCollection.last() ); - - await expect( usePageContextToggle ).toBeChecked(); - } ); - - test( 'allows filtering in non-archive context', async ( { - pageObject, - editor, - page, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await pageObject.insertProductCollection(); - await pageObject.chooseCollectionInPost( 'productCatalog' ); - - await expect( pageObject.products ).toHaveCount( 18 ); - - await page.getByLabel( 'Toggle block inserter' ).click(); - await page.getByRole( 'tab', { name: 'Patterns' } ).click(); - await page - .getByPlaceholder( 'Search' ) - .fill( 'product filters' ); - await page.getByLabel( 'Product Filters' ).click(); - - const postId = await editor.publishPost(); - await page.goto( `/?p=${ postId }` ); - - const productCollection = page.locator( - '.wp-block-woocommerce-product-collection' - ); - - await expect( - productCollection.first().locator( SELECTORS.product ) - ).toHaveCount( 9 ); - await expect( - productCollection.last().locator( SELECTORS.product ) - ).toHaveCount( 9 ); - - await page - .getByRole( 'textbox', { - name: 'Filter products by maximum', - } ) - .dblclick(); - await page.keyboard.type( '10' ); - await page.keyboard.press( 'Tab' ); - - await expect( - productCollection.first().locator( SELECTORS.product ) - ).toHaveCount( 1 ); - await expect( - productCollection.last().locator( SELECTORS.product ) - ).toHaveCount( 9 ); - } ); - - test( 'correctly combines editor and front-end filters', async ( { - pageObject, - editor, - page, - } ) => { - await pageObject.createNewPostAndInsertBlock(); - - await expect( pageObject.products ).toHaveCount( 9 ); - - await pageObject.addFilter( 'Show product categories' ); - await pageObject.setFilterComboboxValue( 'Product categories', [ - 'Music', - ] ); - - await page.getByLabel( 'Toggle block inserter' ).click(); - await page.getByRole( 'tab', { name: 'Patterns' } ).click(); - await page - .getByPlaceholder( 'Search' ) - .fill( 'product filters' ); - await page.getByLabel( 'Product Filters' ).click(); - - await expect( pageObject.products ).toHaveCount( 2 ); - - const postId = await editor.publishPost(); - await page.goto( `/?p=${ postId }` ); - await pageObject.refreshLocators( 'frontend' ); - - await expect( pageObject.products ).toHaveCount( 2 ); - - await page - .getByRole( 'textbox', { - name: 'Filter products by maximum', - } ) - .dblclick(); - await page.keyboard.type( '5' ); - await page.keyboard.press( 'Tab' ); - - await expect( pageObject.products ).toHaveCount( 1 ); - } ); - } ); - } ); - test.describe( 'Toolbar settings', () => { test.beforeEach( async ( { pageObject } ) => { await pageObject.createNewPostAndInsertBlock(); diff --git a/plugins/woocommerce/changelog/test-50444-inspector-control b/plugins/woocommerce/changelog/test-50444-inspector-control new file mode 100644 index 00000000000..fb469b0c0ad --- /dev/null +++ b/plugins/woocommerce/changelog/test-50444-inspector-control @@ -0,0 +1,4 @@ +Significance: minor +Type: tweak + +Move the inspector controls e2e tests from product collection file to its own file From 4608681b6869ebf52aa9cd41a5f3fea2f8f8ae5f Mon Sep 17 00:00:00 2001 From: Andrew Wikel Date: Thu, 22 Aug 2024 14:05:51 -0700 Subject: [PATCH 079/185] Create Review Guidelines documentation page, and fix a typo. (#50248) * Fix typo Fixed one typo * Create reviews-guidelines.md Creating the first draft of the Operation Star guidelines for partners to improve reviews and ratings. * Adding more info and feedback! adding info from https://wooengineering.wordpress.com/2024/07/30/closing-the-loop-enhancing-product-reviews-through-integrated-feedback/ * Update docs manifest * Update menu_title for consistency * Standardize language + remove unsupported characters from review doc * Atomize review docs into subcategory + subpages * Fix linting issues * Update docs manifest with linter fixes --------- Co-authored-by: Jacklyn Biggin --- docs/docs-manifest.json | 71 ++++++++++++++++++- docs/quality-and-best-practices/README.md | 2 +- .../review-guidelines/README.md | 19 +++++ .../how-to-request-reviews.md | 39 ++++++++++ .../review-guidelines/misc-guidelines.md | 14 ++++ .../notifying-users-about-important-events.md | 18 +++++ .../responding-to-negative-reviews.md | 33 +++++++++ .../utilizing-feature-requests.md | 31 ++++++++ .../utilizing-your-support-team.md | 18 +++++ .../when-to-request-reviews.md | 24 +++++++ 10 files changed, 265 insertions(+), 4 deletions(-) create mode 100644 docs/quality-and-best-practices/review-guidelines/README.md create mode 100644 docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md create mode 100644 docs/quality-and-best-practices/review-guidelines/misc-guidelines.md create mode 100644 docs/quality-and-best-practices/review-guidelines/notifying-users-about-important-events.md create mode 100644 docs/quality-and-best-practices/review-guidelines/responding-to-negative-reviews.md create mode 100644 docs/quality-and-best-practices/review-guidelines/utilizing-feature-requests.md create mode 100644 docs/quality-and-best-practices/review-guidelines/utilizing-your-support-team.md create mode 100644 docs/quality-and-best-practices/review-guidelines/when-to-request-reviews.md diff --git a/docs/docs-manifest.json b/docs/docs-manifest.json index 9537ea57ba4..6b037a8179a 100644 --- a/docs/docs-manifest.json +++ b/docs/docs-manifest.json @@ -1119,7 +1119,7 @@ ] }, { - "content": "\nEnsuring the quality of your WooCommerce projects is essential. This section will delve into quality exoectations, best practices, coding standards, and other methodologies to ensure your projects stand out in terms of reliability, efficiency, user experience, and more. \n", + "content": "\nEnsuring the quality of your WooCommerce projects is essential. This section will delve into quality expectations, best practices, coding standards, and other methodologies to ensure your projects stand out in terms of reliability, efficiency, user experience, and more. \n", "category_slug": "quality-and-best-practices", "category_title": "Quality And Best Practices", "posts": [ @@ -1244,7 +1244,72 @@ "id": "b09a572b8a452b6cd795e0985daa85f06e5889fb" } ], - "categories": [] + "categories": [ + { + "content": "\nReviews are an integral part of the online shopping experience, and people installing software pay attention to them. Prospective users of your extensions will likely consider average ratings when making software choices.\n\nMany of today's most popular online review platforms — from Yelp business reviews, to Amazon product reviews — have a range of opinion that can be polarized, with many extremely positive and/or negative reviews, and fewer moderate opinions. This creates a \"J-shaped\" distribution of reviews that isn't as accurate or as helpful as could be.\n\nWooCommerce.com and WordPress.org both feature reviews heavily, and competing extensions having a higher rating likely have the edge in user choice. \n\n## Primary considerations around reviews\n\nRequesting more reviews for a extension with major issues will not generate good reviews, and analyzing existing reviews will help surface areas to address before soliciting reviews.\n\nIt is extremely rare for users of WordPress plugins to leave reviews organically (.2% of users for WordPress.org leave reviews), which means that there's an untapped market of 99.8% of users of the average plugin.\n\nThese plugins are competing with other plugins on the same search terms in the WordPress.org plugin directory, and ratings are a large factor in the ranking algorithm. This is not usually a factor to the same extent on the WooCommerce Marketplace. For instance, WooCommerce's PayPal extension directly competes on all possible keywords with other PayPal extensions on the WordPress.org repository, while it does not compete with other PayPal payments extensions on the Marketplace.\n", + "category_slug": "review-guidelines", + "category_title": "Review Guidelines", + "posts": [ + { + "post_title": "When to request WooCommerce extension reviews", + "menu_title": "When to review reviews", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/when-to-request-reviews.md", + "hash": "b104db2cd0a8ff6ebac8ae93e5908f518f83c927e867f94b3745290e32af980b", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/when-to-request-reviews.md", + "id": "d40eb30ff49c89545a5918f5b8c08b82e6f8f45a" + }, + { + "post_title": "Utilizing your support team to respond to feedback", + "menu_title": "Utilizing your support team", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/utilizing-your-support-team.md", + "hash": "3cadfdd506c2c279c16d411b4037f6ea6cd2fa2dcfad6ffe895e89e61b0e54c0", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/utilizing-your-support-team.md", + "id": "f7029c8549d5ed86dd8f9cc27d7a62da539b9ba7" + }, + { + "post_title": "Utilizing WooCommerce extension feature requests", + "menu_title": "Utilizing feature requests", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/utilizing-feature-requests.md", + "hash": "28af9f05e0c843a932ba1320d16097c029e71bdeae0dbe02ff95a96eb9d8c1c0", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/utilizing-feature-requests.md", + "id": "4efca02b0f14b13a1471f5beec4ef15365f98b17" + }, + { + "post_title": "How to respond to negative WooCommerce extension reviews", + "menu_title": "Responding to negative reviews", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/responding-to-negative-reviews.md", + "hash": "306df15c394c6867657e7c68282f16dab5d08e821bbb7e27514abca764262b24", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/responding-to-negative-reviews.md", + "id": "7cb825a3830e392aeae853b441a91237f48c3ae5" + }, + { + "post_title": "Notifying users about bug fixes and features requests", + "menu_title": "Notifying users about bug fixes and feature requests", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/notifying-users-about-important-events.md", + "hash": "4e1508499ff11586680af208f3b90afba4c482d75aca25bc4ed18bfd1590f7e7", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/notifying-users-about-important-events.md", + "id": "9ccc4bf579cc624002478fe8706241f4640d92b8" + }, + { + "post_title": "Miscellaneous guidelines and advice", + "menu_title": "Miscellaneous guidelines", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/misc-guidelines.md", + "hash": "c5515db05195cebbe1ed0595dbf2a09623c3b85e1b5b6e1c3628a79b957f8884", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/misc-guidelines.md", + "id": "003ece0250c6a0c248019a095f75f3cfedbc290e" + }, + { + "post_title": "How to request WooCommerce extension reviews", + "menu_title": "Requesting reviews", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md", + "hash": "5a77783c32c1bb0fefc6888f7a3217fe6e5c7242692593a17828b2f1ffec618b", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md", + "id": "3d0c8bf7339a71198737d19eec7e6d71697b3727" + } + ], + "categories": [] + } + ] }, { "content": "\nUnderstand Woo's reporting capabilities. Learn to generate, understand, and optimize reports to make informed decisions about your WooCommerce projects.\n", @@ -1731,5 +1796,5 @@ "categories": [] } ], - "hash": "b6fab4eae1266824ee3e876c8fa5fd0342f59b4a0e5978f1460afc67d82e6d94" + "hash": "aed8797ef51eef8ebc3d29337a5c1e2eb321e45ee45cd20b297246ee2ec72c44" } \ No newline at end of file diff --git a/docs/quality-and-best-practices/README.md b/docs/quality-and-best-practices/README.md index ff7323fc62c..f68726dbcc5 100644 --- a/docs/quality-and-best-practices/README.md +++ b/docs/quality-and-best-practices/README.md @@ -4,4 +4,4 @@ category_slug: quality-and-best-practices post_title: Quality and best practices --- -Ensuring the quality of your WooCommerce projects is essential. This section will delve into quality exoectations, best practices, coding standards, and other methodologies to ensure your projects stand out in terms of reliability, efficiency, user experience, and more. +Ensuring the quality of your WooCommerce projects is essential. This section will delve into quality expectations, best practices, coding standards, and other methodologies to ensure your projects stand out in terms of reliability, efficiency, user experience, and more. diff --git a/docs/quality-and-best-practices/review-guidelines/README.md b/docs/quality-and-best-practices/review-guidelines/README.md new file mode 100644 index 00000000000..0fa61587032 --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/README.md @@ -0,0 +1,19 @@ +--- +category_title: Review Guidelines +category_slug: review-guidelines +post_title: Review Guidelines +--- + +Reviews are an integral part of the online shopping experience, and people installing software pay attention to them. Prospective users of your extensions will likely consider average ratings when making software choices. + +Many of today's most popular online review platforms — from Yelp business reviews, to Amazon product reviews — have a range of opinion that can be polarized, with many extremely positive and/or negative reviews, and fewer moderate opinions. This creates a "J-shaped" distribution of reviews that isn't as accurate or as helpful as could be. + +WooCommerce.com and WordPress.org both feature reviews heavily, and competing extensions having a higher rating likely have the edge in user choice. + +## Primary considerations around reviews + +Requesting more reviews for a extension with major issues will not generate good reviews, and analyzing existing reviews will help surface areas to address before soliciting reviews. + +It is extremely rare for users of WordPress plugins to leave reviews organically (.2% of users for WordPress.org leave reviews), which means that there's an untapped market of 99.8% of users of the average plugin. + +These plugins are competing with other plugins on the same search terms in the WordPress.org plugin directory, and ratings are a large factor in the ranking algorithm. This is not usually a factor to the same extent on the WooCommerce Marketplace. For instance, WooCommerce's PayPal extension directly competes on all possible keywords with other PayPal extensions on the WordPress.org repository, while it does not compete with other PayPal payments extensions on the Marketplace. diff --git a/docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md b/docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md new file mode 100644 index 00000000000..0654903ecaa --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md @@ -0,0 +1,39 @@ +--- +post_title: How to request WooCommerce extension reviews +menu_title: Requesting reviews +--- + +## Methods of requesitng reviews + +### Admin notices + +Admin notices are an industry standard method of requesting reviews, but bombarding the admin dashboard with admin notices is not effective. We recommend using restraint in the design of a notice, as well as limiting to a single notice at a time. It's very easy to overwhelm merchants with too many notices, or too intrusive notices. + +#### Recommendations + +* A good place for an admin notice to review an extension would be to show on the `Plugins` page and extension's settings pages. +* Include a snooze option (or multiple) on your notices with a clear expectation of when the notice will reappear. +* Admin notices should always be always be completely dismissable. They cannot only have a snooze option. +* The options presented in the notice must be phrased carefully to avoid manipulative language. +* Use consistently designed notices so the request for reviews feels like a part of your extension, and looks consistent with WooCommerce's design. + +### Direct contact + +#### Recommendations + +* The most direct route to requesting reviews with the highest chance of being positive is to contact the customer when they are the happiest with the product. +* This can be milestone or time based, following the timing guidelines below. +* The best method for this is either an email or other direct exchange (support chat, call, etc.). This has the highest conversion rate, especially when timed properly so that the customer is happiest. +* This is also extremely effective when you are able to request feedback from specifically qualified merchants, such as merchants that have processed a certain amount with your platform, or who have shipped their first 100 orders using your fulfillment extension, or similar. +* Direct outreach is most likely to be successful if you have ways of targeting users for review requests (merchant account / usage info, etc.), as well as ways to gather the reviews, like sales or marketing teams able to email/call/chat with merchants. + +## Messaging for requesting reviews + +One method of requesting feedback that we recommend is using the NPS style of review solicitation. This can allow for an increase positive reviews as well as providing the opportunity to assist merchants that are struggling. + +NPS-style reviews first ask the user how they rate the product (out of 5 stars), then route them based on their response: + +* If they click 4 or 5 stars, ask them to leave a review. +* If they click 1, 2 or 3, tell them we're here to help & ask them to submit a support ticket. + +Merchants are significantly more likely to leave a review after a positive support interaction with a support rep who explicitly asked for a review. The language "the best way to thank me is to leave a 5 star review that mentions me in it" or similar tends to work very well - people are more willing to help a person than a produc or company. diff --git a/docs/quality-and-best-practices/review-guidelines/misc-guidelines.md b/docs/quality-and-best-practices/review-guidelines/misc-guidelines.md new file mode 100644 index 00000000000..dde408b1400 --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/misc-guidelines.md @@ -0,0 +1,14 @@ +--- +post_title: Miscellaneous guidelines and advice +menu_title: Miscellaneous guidelines +--- + +Contributors' names matching search terms directly will rank extremely highly on the WordPress.org plugin repo, which means that having a WordPress.org user named after your business (if that's a search term for your plugin) could tilt the scales over a competing plugin. + +Constant nags and overwhelming the admin dashboard with unnecessary alerts detract from your user experience. + +You can request to have reviews that are not actually feedback removed. Where this might be applicable is if the request is a simple support request, where it's obviously in the wrong spot. 1 star reviews, even if aggressive or angry, are not usually removed. + +Reply to reviews! Thank the giver for offering feedback, acknowledge the issue if needed, ask for more specific feedback, or provide an update when that feedback is addressed! Your reviews are a great window into what your extension's users are actually thinking. + +Having folks close to the extension's development (think developers and project managers) looking at reviews on a regular basis is a good way to ensure the customers voice is heard. 1 star reviews are among the most useful, as long as the issue is understood and addressed (if needed). diff --git a/docs/quality-and-best-practices/review-guidelines/notifying-users-about-important-events.md b/docs/quality-and-best-practices/review-guidelines/notifying-users-about-important-events.md new file mode 100644 index 00000000000..00f562f13e6 --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/notifying-users-about-important-events.md @@ -0,0 +1,18 @@ +--- +post_title: Notifying users about bug fixes and features requests +menu_title: Notifying users about bug fixes and feature requests +--- + +A bug or a missing feature can be a showstopper for merchants. Bugs that pile up or popular features that are not implemented can lead to negative reviews and/or merchants churning and looking at a competitive solution. + +Bugs are usually reported via support or GitHub, or you can discover them yourselves in testing. + +When a critical bug is found, resolve it within a couple of days (most critical bugs should be resolved within 24 hours) and release a new plugin version promptly. Part of your release process should be to notify all stakeholders (the support team and the merchant affected) about the upcoming release. + +Even though a critical bug is a great source of stress for merchants, a quick resolution makes merchants feel heard and supported — having a reliable business partner, who is keen to help in the most difficult situation, helps build a stronger relationship. Therefore, we usually ask merchants for a 5* review when we deliver a fast solution. + +When you implement a new feature request and ship a new plugin version, you can follow a similar approach to bugs: + +* Notify all stakeholders. +* Update the relevant request in the Feature Requests board, by sharing a public update and marking it as 'Completed'. +* For breaking releases: communicating with your marketing/relations teams to publish updates/newsletters before the release. diff --git a/docs/quality-and-best-practices/review-guidelines/responding-to-negative-reviews.md b/docs/quality-and-best-practices/review-guidelines/responding-to-negative-reviews.md new file mode 100644 index 00000000000..1bac36640da --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/responding-to-negative-reviews.md @@ -0,0 +1,33 @@ +--- +post_title: How to respond to negative WooCommerce extension reviews +menu_title: Responding to negative reviews +--- + +An unpleasant event in the merchant's journey can lead them to leave a public, negative review. These events usually are: + +* a problem with the product, +* a missing product feature, +* an unhelpful reply, +* long wait times to receive a reply, or; +* combinations of the above. + +When receiving a negative review, your goal should always be to turn this review around - this sounds tough, but it is really rewarding. + +In the majority of cases, merchants who leave a negative review have first tried contacting support for help. This is useful knowledge, as we can read through the conversation history, understand the issue the merchant experienced and share more details with them when we reach out, even from our first reply. + +The process we have seen work well is: + +* Create a new response (via email, or on a public review) with subject: Regarding your recent review for xxx. +* Start by introducing yourself, for example: "Hey there, This is Andrew from the team that develops xxx". +* Use empathetic language and make it clear that this negative review had an impact on you. For example, "I read your recent review for xxx and I am worried to hear that an issue is preventing you from using this plugin as you had in mind. I'd be happy to help you resolve this!". + +Compare the above sentence with: "I am sorry to hear that you experienced an issue with xxx". "I am sorry to" indicates that you are saddened by an event, but don't necessarily plan to do something about it. In comparison, in "I am worried to hear", worry indicates action. Additionally, "That you experienced an issue" can be interpreted as if the problem is mainly the merchant's fault, whereas language like "an issue is preventing you from using this plugin as you had in mind. I'd be happy to help you resolve this!" implies you and the merchant are on the same team. + +* Share more details, a solution, an idea, a suggestion or an explanation. +* Urge the merchant to update the review, by highlighting how important reviews are for our team and for other merchants. Example language to do this is "We would appreciate it if you could take a couple of minutes to update your review and describe your experience with our product and support. Honest reviews are extremely helpful for other merchants who try to decide if a plugin is a right fit for them. Thank you for your contribution!". +* Include a direct link to the reviews section, so merchants can easily navigate there and change their review. +* On a follow-up communication, if the merchant has changed the review, consider saying something like: "I shared this with the rest of the team and it made everyone's day". + +If the above things are true, sharing some of your procedures with merchants (highlighting how your team emphasizes and thrives on feedback) helps ensure merchants feel like you are part of their team and builds a strong relationship with them. + +Even a merchant that doesn't change their review can offer a mutually beneficial discussion by learning more about their setup and offering some suggestions. These conversations help grow merchants' trust. diff --git a/docs/quality-and-best-practices/review-guidelines/utilizing-feature-requests.md b/docs/quality-and-best-practices/review-guidelines/utilizing-feature-requests.md new file mode 100644 index 00000000000..4a10042be0f --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/utilizing-feature-requests.md @@ -0,0 +1,31 @@ +--- +post_title: Utilizing WooCommerce extension feature requests +menu_title: Utilizing feature requests +--- + +It is important to keep track of all feature requests, and have some sort of system of record where anyone can see what kind of feedback the product is receiving over time. + +We recommend a daily or bi-daily check-in, where you: + +* triage new feature requests, +* celebrate positive reviews and; +* act upon negative reviews. + +Carefully maintaining feature request boards (or similar system) is key, as the average board contains a lot of duplicate/spam content, requests about features that have been implemented and requests about features that will likely never be implemented. Poorly maintained boards make merchants feel unheard/neglected. + +This results in more negative reviews on the premise that the product teams were not reading/listening to their feedback. + +We've seen good results with the following procedures: + +Starting with the most affected products, go through all open requests, reply to most/all of them and categorize them as: + +* "Open", for requests that we still want more feedback, +* "Planned", for requests that we plan to implement, +* "Completed", for requests that have already been implemented and; +* "Closed", for requests that we do not plan to implement, as they are not a good fit for the product, for duplicate/spam requests and for requests that were actually support questions. + +Replying to all "Open" requests is the goal, but if that's not attainable currently, make sure to reply to 100% of the requests that are closed. + +For new open requests that arrive as a feature request, discuss/triage them, reply promptly, and assign a status to avoid having the board become unmanaged, and ensure merchants feel (and are) heard. + +In addition to the effect a tidy board has on merchants, it also helps product teams better understand which requests are most wanted and most impactful and then plan work accordingly. diff --git a/docs/quality-and-best-practices/review-guidelines/utilizing-your-support-team.md b/docs/quality-and-best-practices/review-guidelines/utilizing-your-support-team.md new file mode 100644 index 00000000000..80eecb20207 --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/utilizing-your-support-team.md @@ -0,0 +1,18 @@ +--- +post_title: Utilizing your support team to respond to feedback +menu_title: Utilizing your support team +--- + +Your support team is usually the primary contact point of merchants when they contact you. Tickets and chats are the best tools we have to converse with merchants, understand pain-points about our software, listen to their feedback and analyze their feature requests. Collectively, support teams have a great understanding of the products and how people use them. This information is essential to be transferred over to product and engineering teams. + +We recommend that you take the following steps to best utilize your support team: + +* Create a strict internal SLA where support team requests are answered by product or engineering teams. +* Ensure you have a way for your support team to effectively report bugs to your product and engineering teams. +* When responding to your support team, avoid super-short answers, and try to explain the answer simply and concisely. This will allow the support agent to copy/paste your answer to the merchant. +* Avoid replying with statements like "no, this is not possible" or "no, this feature will not be implemented" without providing additional context about technical or product limitations. +* Regularly dedicate additional time to implement a short custom code snippets or to provide in-depth technical details about how a custom project would be implemented so that merchants can reach a solution faster if they decide to hire a dedicated WooCommerce developer. A small effort can go a long way to amaze merchants and reveal an opportunity to request a 5 star review. +* Keep support in the loop when they report a bug or request a new feature. When you release a new product version, we always consider the impact it can have on support. +* Work closely with your support team. For example, consider having a feedback hangout call every month where you can discuss product feedback and planned improvements. + +With these kinds of practices in place, support teams are more willing to share feedback, issues, concerns, and questions with us. This helps maintain a closer relationship with merchants and identify pain-points early, before they become a reason for them to churn. diff --git a/docs/quality-and-best-practices/review-guidelines/when-to-request-reviews.md b/docs/quality-and-best-practices/review-guidelines/when-to-request-reviews.md new file mode 100644 index 00000000000..eb7912f7336 --- /dev/null +++ b/docs/quality-and-best-practices/review-guidelines/when-to-request-reviews.md @@ -0,0 +1,24 @@ +--- +post_title: When to request WooCommerce extension reviews +menu_title: When to review reviews +--- + +The best approach to increasing our top-star reviews is to identify key moments in the merchant's journey, when they are more likely to leave a review and actively request for it. + +The most distinct moments for most of our use cases are: + +* When merchants feel helpless, lost, frustrated and we are able to help, +* When merchants find a bug in our code and we quickly ship a fix, +* When merchants need a feature and we notify them when it is shipped, +* When merchants feel alone and we make them feel heard and; +* When merchants contact with a question and we go out of our way to provide them with top-notch support, even if this means slightly stepping outside the official boundaries of a support policy. + +Think about who is seeing the review request, and what they are doing at that time. Showing a request to a fulfillment worker just trying to ship an order isn't likely going to work well. + +Outreach after a milestone works really well. Some language we've used before is "Congratulations on your xxth sale! We're delighted that WooPayments facilitated this milestone. Would you consider sharing your experience and encouraging others by reviewing our extension?". + +Another way to optimally time a review request would be to setup a prompt that aligns with use patterns. For instance, if you know that most of your merchants use your extension daily, you would likely send a review request sooner than a extension that most merchants interact very sparingly with. + +SaaS/Connector extensions need to be particularly careful about requesting ratings correctly, as they are the most likely to be overlooked unless there is an issue, leading to skewed ratings not representative of the actual extension. + +Consider requesting feedback at the end of every single support interaction, especially in the WordPress.org support forums. One of the largest barriers to leaving a review is the requirement of a user being logged into WooCommerce.com (or WordPress.org), and the WordPress.org support forums present a good opportunity to gather these reviews. By being highly responsive in the public support forum and solving issues there, users are already logged in and able to immediately leave a review (after being requested to!). From 3665892ce095e1fe99a62611847689387aa28110 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:29:55 -0300 Subject: [PATCH 080/185] Update changelog.txt from release 9.2.2 (#50893) Prep trunk post release 9.2.2 Co-authored-by: WooCommerce Bot --- changelog.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/changelog.txt b/changelog.txt index 8d70dfca5bc..ed1be0eb305 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,13 @@ == Changelog == += 9.2.2 2024-08-22 = + +**WooCommerce** + +* Fix - Revert PR#48731 to address possible issues with plugins using WC's bundled select2 package. [#50854](https://github.com/woocommerce/woocommerce/pull/50854) +* Fix - Partially revert PR#48709 as it could cause issues for some users of the REST API system_status endpoint. [#50881](https://github.com/woocommerce/woocommerce/pull/50881) + + = 9.2.1 2024-08-21 = **WooCommerce** From ff0a2c7ced1200de52f510f7bff3aa9e5fc362d4 Mon Sep 17 00:00:00 2001 From: "Jorge A. Torres" Date: Thu, 22 Aug 2024 18:52:16 -0300 Subject: [PATCH 081/185] Bump stable tag after 9.2.2 (#50895) Update stable tag --- plugins/woocommerce/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/readme.txt b/plugins/woocommerce/readme.txt index 04146902c1c..986ef663a9f 100644 --- a/plugins/woocommerce/readme.txt +++ b/plugins/woocommerce/readme.txt @@ -4,7 +4,7 @@ Tags: online store, ecommerce, shop, shopping cart, sell online Requires at least: 6.5 Tested up to: 6.6 Requires PHP: 7.4 -Stable tag: 9.2.1 +Stable tag: 9.2.2 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html From 06f441fde60ef3d114cb891cfd119d256cf465cf Mon Sep 17 00:00:00 2001 From: "Jorge A. Torres" Date: Thu, 22 Aug 2024 20:05:55 -0300 Subject: [PATCH 082/185] Cherry-pick PR#50854 into trunk (#50896) * Revert "Drop Select2 in Backwards compatable manner (#48731)" This reverts commit 8f98a2a0577c08943a297ea4b39805f75a8b2311. * Fix linting issue --------- Co-authored-by: Naman Malhotra --- .../client/legacy/js/select2/select2.full.js | 6436 +++++++++++++++++ .../client/legacy/js/select2/select2.js | 5725 +++++++++++++++ .../includes/admin/class-wc-admin-assets.php | 2 +- .../includes/class-wc-frontend-scripts.php | 4 +- 4 files changed, 12164 insertions(+), 3 deletions(-) create mode 100644 plugins/woocommerce/client/legacy/js/select2/select2.full.js create mode 100644 plugins/woocommerce/client/legacy/js/select2/select2.js diff --git a/plugins/woocommerce/client/legacy/js/select2/select2.full.js b/plugins/woocommerce/client/legacy/js/select2/select2.full.js new file mode 100644 index 00000000000..e750834ef5d --- /dev/null +++ b/plugins/woocommerce/client/legacy/js/select2/select2.full.js @@ -0,0 +1,6436 @@ +/*! + * Select2 4.0.3 + * https://select2.github.io + * + * Released under the MIT license + * https://github.com/select2/select2/blob/master/LICENSE.md + */ +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function (jQuery) { + // This is needed so we can catch the AMD loader configuration and use it + // The inner file should be wrapped (by `banner.start.js`) in a function that + // returns the AMD loader references. + var S2 = +(function () { + // Restore the Select2 AMD loader so it can be used + // Needed mostly in the language files, where the loader is not inserted + if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) { + var S2 = jQuery.fn.select2.amd; + } +var S2;(function () { if (!S2 || !S2.requirejs) { +if (!S2) { S2 = {}; } else { require = S2; } +/** + * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/almond for details + */ +//Going sloppy to avoid 'use strict' string cost, but strict practices should +//be followed. +/*jslint sloppy: true */ +/*global setTimeout: false */ + +var requirejs, require, define; +(function (undef) { + var main, req, makeMap, handlers, + defined = {}, + waiting = {}, + config = {}, + defining = {}, + hasOwn = Object.prototype.hasOwnProperty, + aps = [].slice, + jsSuffixRegExp = /\.js$/; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @returns {String} normalized name + */ + function normalize(name, baseName) { + var nameParts, nameSegment, mapValue, foundMap, lastIndex, + foundI, foundStarMap, starI, i, j, part, + baseParts = baseName && baseName.split("/"), + map = config.map, + starMap = (map && map['*']) || {}; + + //Adjust any relative paths. + if (name && name.charAt(0) === ".") { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + name = name.split('/'); + lastIndex = name.length - 1; + + // Node .js allowance: + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } + + //Lop off the last part of baseParts, so that . matches the + //"directory" and not name of the baseName's module. For instance, + //baseName of "one/two/three", maps to "one/two/three.js", but we + //want the directory, "one/two" for this normalization. + name = baseParts.slice(0, baseParts.length - 1).concat(name); + + //start trimDots + for (i = 0; i < name.length; i += 1) { + part = name[i]; + if (part === ".") { + name.splice(i, 1); + i -= 1; + } else if (part === "..") { + if (i === 1 && (name[2] === '..' || name[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + name.splice(i - 1, 2); + i -= 2; + } + } + } + //end trimDots + + name = name.join("/"); + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if ((baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join("/"); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = map[baseParts.slice(0, j).join('/')]; + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = mapValue[nameSegment]; + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function makeRequire(relName, forceSync) { + return function () { + //A version of a require function that passes a moduleName + //value for items that may need to + //look up paths relative to the moduleName + var args = aps.call(arguments, 0); + + //If first arg is not require('string'), and there is only + //one arg, it is the array form without a callback. Insert + //a null so that the following concat is correct. + if (typeof args[0] !== 'string' && args.length === 1) { + args.push(null); + } + return req.apply(undef, args.concat([relName, forceSync])); + }; + } + + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(depName) { + return function (value) { + defined[depName] = value; + }; + } + + function callDep(name) { + if (hasProp(waiting, name)) { + var args = waiting[name]; + delete waiting[name]; + defining[name] = true; + main.apply(undef, args); + } + + if (!hasProp(defined, name) && !hasProp(defining, name)) { + throw new Error('No ' + name); + } + return defined[name]; + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Makes a name map, normalizing the name, and using a plugin + * for normalization if necessary. Grabs a ref to plugin + * too, as an optimization. + */ + makeMap = function (name, relName) { + var plugin, + parts = splitPrefix(name), + prefix = parts[0]; + + name = parts[1]; + + if (prefix) { + prefix = normalize(prefix, relName); + plugin = callDep(prefix); + } + + //Normalize according + if (prefix) { + if (plugin && plugin.normalize) { + name = plugin.normalize(name, makeNormalize(relName)); + } else { + name = normalize(name, relName); + } + } else { + name = normalize(name, relName); + parts = splitPrefix(name); + prefix = parts[0]; + name = parts[1]; + if (prefix) { + plugin = callDep(prefix); + } + } + + //Using ridiculous property names for space reasons + return { + f: prefix ? prefix + '!' + name : name, //fullName + n: name, + pr: prefix, + p: plugin + }; + }; + + function makeConfig(name) { + return function () { + return (config && config.config && config.config[name]) || {}; + }; + } + + handlers = { + require: function (name) { + return makeRequire(name); + }, + exports: function (name) { + var e = defined[name]; + if (typeof e !== 'undefined') { + return e; + } else { + return (defined[name] = {}); + } + }, + module: function (name) { + return { + id: name, + uri: '', + exports: defined[name], + config: makeConfig(name) + }; + } + }; + + main = function (name, deps, callback, relName) { + var cjsModule, depName, ret, map, i, + args = [], + callbackType = typeof callback, + usingExports; + + //Use name if no relName + relName = relName || name; + + //Call the callback to define the module, if necessary. + if (callbackType === 'undefined' || callbackType === 'function') { + //Pull out the defined dependencies and pass the ordered + //values to the callback. + //Default to [require, exports, module] if no deps + deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; + for (i = 0; i < deps.length; i += 1) { + map = makeMap(deps[i], relName); + depName = map.f; + + //Fast path CommonJS standard dependencies. + if (depName === "require") { + args[i] = handlers.require(name); + } else if (depName === "exports") { + //CommonJS module spec 1.1 + args[i] = handlers.exports(name); + usingExports = true; + } else if (depName === "module") { + //CommonJS module spec 1.1 + cjsModule = args[i] = handlers.module(name); + } else if (hasProp(defined, depName) || + hasProp(waiting, depName) || + hasProp(defining, depName)) { + args[i] = callDep(depName); + } else if (map.p) { + map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); + args[i] = defined[depName]; + } else { + throw new Error(name + ' missing ' + depName); + } + } + + ret = callback ? callback.apply(defined[name], args) : undefined; + + if (name) { + //If setting exports via "module" is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + if (cjsModule && cjsModule.exports !== undef && + cjsModule.exports !== defined[name]) { + defined[name] = cjsModule.exports; + } else if (ret !== undef || !usingExports) { + //Use the return value from the function. + defined[name] = ret; + } + } + } else if (name) { + //May just be an object definition for the module. Only + //worry about defining if have a module name. + defined[name] = callback; + } + }; + + requirejs = require = req = function (deps, callback, relName, forceSync, alt) { + if (typeof deps === "string") { + if (handlers[deps]) { + //callback in this case is really relName + return handlers[deps](callback); + } + //Just return the module wanted. In this scenario, the + //deps arg is the module name, and second arg (if passed) + //is just the relName. + //Normalize module name, if it contains . or .. + return callDep(makeMap(deps, callback).f); + } else if (!deps.splice) { + //deps is a config object, not an array. + config = deps; + if (config.deps) { + req(config.deps, config.callback); + } + if (!callback) { + return; + } + + if (callback.splice) { + //callback is an array, which means it is a dependency list. + //Adjust args if there are dependencies + deps = callback; + callback = relName; + relName = null; + } else { + deps = undef; + } + } + + //Support require(['a']) + callback = callback || function () {}; + + //If relName is a function, it is an errback handler, + //so remove it. + if (typeof relName === 'function') { + relName = forceSync; + forceSync = alt; + } + + //Simulate async callback; + if (forceSync) { + main(undef, deps, callback, relName); + } else { + //Using a non-zero value because of concern for what old browsers + //do, and latest browsers "upgrade" to 4 if lower value is used: + //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: + //If want a value immediately, use require('id') instead -- something + //that works in almond on the global level, but not guaranteed and + //unlikely to work in other AMD implementations. + setTimeout(function () { + main(undef, deps, callback, relName); + }, 4); + } + + return req; + }; + + /** + * Just drops the config on the floor, but returns req in case + * the config return value is used. + */ + req.config = function (cfg) { + return req(cfg); + }; + + /** + * Expose module registry for debugging and tooling + */ + requirejs._defined = defined; + + define = function (name, deps, callback) { + if (typeof name !== 'string') { + throw new Error('See almond README: incorrect module build, no module name'); + } + + //This module may not have dependencies + if (!deps.splice) { + //deps is not an array, so probably means + //an object literal or factory function for + //the value. Adjust args. + callback = deps; + deps = []; + } + + if (!hasProp(defined, name) && !hasProp(waiting, name)) { + waiting[name] = [name, deps, callback]; + } + }; + + define.amd = { + jQuery: true + }; +}()); + +S2.requirejs = requirejs;S2.require = require;S2.define = define; +} +}()); +S2.define("almond", function(){}); + +/* global jQuery:false, $:false */ +S2.define('jquery',[],function () { + var _$ = jQuery || $; + + if (_$ == null && console && console.error) { + console.error( + 'Select2: An instance of jQuery or a jQuery-compatible library was not ' + + 'found. Make sure that you are including jQuery before Select2 on your ' + + 'web page.' + ); + } + + return _$; +}); + +S2.define('select2/utils',[ + 'jquery' +], function ($) { + var Utils = {}; + + Utils.Extend = function (ChildClass, SuperClass) { + var __hasProp = {}.hasOwnProperty; + + function BaseConstructor () { + this.constructor = ChildClass; + } + + for (var key in SuperClass) { + if (__hasProp.call(SuperClass, key)) { + ChildClass[key] = SuperClass[key]; + } + } + + BaseConstructor.prototype = SuperClass.prototype; + ChildClass.prototype = new BaseConstructor(); + ChildClass.__super__ = SuperClass.prototype; + + return ChildClass; + }; + + function getMethods (theClass) { + var proto = theClass.prototype; + + var methods = []; + + for (var methodName in proto) { + var m = proto[methodName]; + + if (typeof m !== 'function') { + continue; + } + + if (methodName === 'constructor') { + continue; + } + + methods.push(methodName); + } + + return methods; + } + + Utils.Decorate = function (SuperClass, DecoratorClass) { + var decoratedMethods = getMethods(DecoratorClass); + var superMethods = getMethods(SuperClass); + + function DecoratedClass () { + var unshift = Array.prototype.unshift; + + var argCount = DecoratorClass.prototype.constructor.length; + + var calledConstructor = SuperClass.prototype.constructor; + + if (argCount > 0) { + unshift.call(arguments, SuperClass.prototype.constructor); + + calledConstructor = DecoratorClass.prototype.constructor; + } + + calledConstructor.apply(this, arguments); + } + + DecoratorClass.displayName = SuperClass.displayName; + + function ctr () { + this.constructor = DecoratedClass; + } + + DecoratedClass.prototype = new ctr(); + + for (var m = 0; m < superMethods.length; m++) { + var superMethod = superMethods[m]; + + DecoratedClass.prototype[superMethod] = + SuperClass.prototype[superMethod]; + } + + var calledMethod = function (methodName) { + // Stub out the original method if it's not decorating an actual method + var originalMethod = function () {}; + + if (methodName in DecoratedClass.prototype) { + originalMethod = DecoratedClass.prototype[methodName]; + } + + var decoratedMethod = DecoratorClass.prototype[methodName]; + + return function () { + var unshift = Array.prototype.unshift; + + unshift.call(arguments, originalMethod); + + return decoratedMethod.apply(this, arguments); + }; + }; + + for (var d = 0; d < decoratedMethods.length; d++) { + var decoratedMethod = decoratedMethods[d]; + + DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod); + } + + return DecoratedClass; + }; + + var Observable = function () { + this.listeners = {}; + }; + + Observable.prototype.on = function (event, callback) { + this.listeners = this.listeners || {}; + + if (event in this.listeners) { + this.listeners[event].push(callback); + } else { + this.listeners[event] = [callback]; + } + }; + + Observable.prototype.trigger = function (event) { + var slice = Array.prototype.slice; + var params = slice.call(arguments, 1); + + this.listeners = this.listeners || {}; + + // Params should always come in as an array + if (params == null) { + params = []; + } + + // If there are no arguments to the event, use a temporary object + if (params.length === 0) { + params.push({}); + } + + // Set the `_type` of the first object to the event + params[0]._type = event; + + if (event in this.listeners) { + this.invoke(this.listeners[event], slice.call(arguments, 1)); + } + + if ('*' in this.listeners) { + this.invoke(this.listeners['*'], arguments); + } + }; + + Observable.prototype.invoke = function (listeners, params) { + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i].apply(this, params); + } + }; + + Utils.Observable = Observable; + + Utils.generateChars = function (length) { + var chars = ''; + + for (var i = 0; i < length; i++) { + var randomChar = Math.floor(Math.random() * 36); + chars += randomChar.toString(36); + } + + return chars; + }; + + Utils.bind = function (func, context) { + return function () { + func.apply(context, arguments); + }; + }; + + Utils._convertData = function (data) { + for (var originalKey in data) { + var keys = originalKey.split('-'); + + var dataLevel = data; + + if (keys.length === 1) { + continue; + } + + for (var k = 0; k < keys.length; k++) { + var key = keys[k]; + + // Lowercase the first letter + // By default, dash-separated becomes camelCase + key = key.substring(0, 1).toLowerCase() + key.substring(1); + + if (!(key in dataLevel)) { + dataLevel[key] = {}; + } + + if (k == keys.length - 1) { + dataLevel[key] = data[originalKey]; + } + + dataLevel = dataLevel[key]; + } + + delete data[originalKey]; + } + + return data; + }; + + Utils.hasScroll = function (index, el) { + // Adapted from the function created by @ShadowScripter + // and adapted by @BillBarry on the Stack Exchange Code Review website. + // The original code can be found at + // http://codereview.stackexchange.com/q/13338 + // and was designed to be used with the Sizzle selector engine. + + var $el = $(el); + var overflowX = el.style.overflowX; + var overflowY = el.style.overflowY; + + //Check both x and y declarations + if (overflowX === overflowY && + (overflowY === 'hidden' || overflowY === 'visible')) { + return false; + } + + if (overflowX === 'scroll' || overflowY === 'scroll') { + return true; + } + + return ($el.innerHeight() < el.scrollHeight || + $el.innerWidth() < el.scrollWidth); + }; + + Utils.escapeMarkup = function (markup) { + var replaceMap = { + '\\': '\', + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '/': '/' + }; + + // Do not try to escape the markup if it's not a string + if (typeof markup !== 'string') { + return markup; + } + + return String(markup).replace(/[&<>"'\/\\]/g, function (match) { + return replaceMap[match]; + }); + }; + + // Append an array of jQuery nodes to a given element. + Utils.appendMany = function ($element, $nodes) { + // jQuery 1.7.x does not support $.fn.append() with an array + // Fall back to a jQuery object collection using $.fn.add() + if ($.fn.jquery.substr(0, 3) === '1.7') { + var $jqNodes = $(); + + $.map($nodes, function (node) { + $jqNodes = $jqNodes.add(node); + }); + + $nodes = $jqNodes; + } + + $element.append($nodes); + }; + + return Utils; +}); + +S2.define('select2/results',[ + 'jquery', + './utils' +], function ($, Utils) { + function Results ($element, options, dataAdapter) { + this.$element = $element; + this.data = dataAdapter; + this.options = options; + + Results.__super__.constructor.call(this); + } + + Utils.Extend(Results, Utils.Observable); + + Results.prototype.render = function () { + var $results = $( + '
    ' + ); + + if (this.options.get('multiple')) { + $results.attr('aria-multiselectable', 'true'); + } + + this.$results = $results; + + return $results; + }; + + Results.prototype.clear = function () { + this.$results.empty(); + }; + + Results.prototype.displayMessage = function (params) { + var escapeMarkup = this.options.get('escapeMarkup'); + + this.clear(); + this.hideLoading(); + + var $message = $( + '
  • ' + ); + + var message = this.options.get('translations').get(params.message); + + $message.append( + escapeMarkup( + message(params.args) + ) + ); + + $message[0].className += ' select2-results__message'; + + this.$results.append($message); + }; + + Results.prototype.hideMessages = function () { + this.$results.find('.select2-results__message').remove(); + }; + + Results.prototype.append = function (data) { + this.hideLoading(); + + var $options = []; + + if (data.results == null || data.results.length === 0) { + if (this.$results.children().length === 0) { + this.trigger('results:message', { + message: 'noResults' + }); + } + + return; + } + + data.results = this.sort(data.results); + + for (var d = 0; d < data.results.length; d++) { + var item = data.results[d]; + + var $option = this.option(item); + + $options.push($option); + } + + this.$results.append($options); + }; + + Results.prototype.position = function ($results, $dropdown) { + var $resultsContainer = $dropdown.find('.select2-results'); + $resultsContainer.append($results); + }; + + Results.prototype.sort = function (data) { + var sorter = this.options.get('sorter'); + + return sorter(data); + }; + + Results.prototype.highlightFirstItem = function () { + var $options = this.$results + .find('.select2-results__option[aria-selected]'); + + var $selected = $options.filter('[aria-selected=true]'); + + // Check if there are any selected options + if ($selected.length > 0) { + // If there are selected options, highlight the first + $selected.first().trigger('mouseenter'); + } else { + // If there are no selected options, highlight the first option + // in the dropdown + $options.first().trigger('mouseenter'); + } + + this.ensureHighlightVisible(); + }; + + Results.prototype.setClasses = function () { + var self = this; + + this.data.current(function (selected) { + var selectedIds = $.map(selected, function (s) { + return s.id.toString(); + }); + + var $options = self.$results + .find('.select2-results__option[aria-selected]'); + + $options.each(function () { + var $option = $(this); + + var item = $.data(this, 'data'); + + // id needs to be converted to a string when comparing + var id = '' + item.id; + + if ((item.element != null && item.element.selected) || + (item.element == null && $.inArray(id, selectedIds) > -1)) { + $option.attr('aria-selected', 'true'); + } else { + $option.attr('aria-selected', 'false'); + } + }); + + }); + }; + + Results.prototype.showLoading = function (params) { + this.hideLoading(); + + var loadingMore = this.options.get('translations').get('searching'); + + var loading = { + disabled: true, + loading: true, + text: loadingMore(params) + }; + var $loading = this.option(loading); + $loading.className += ' loading-results'; + + this.$results.prepend($loading); + }; + + Results.prototype.hideLoading = function () { + this.$results.find('.loading-results').remove(); + }; + + Results.prototype.option = function (data) { + var option = document.createElement('li'); + option.className = 'select2-results__option'; + + var attrs = { + 'role': 'treeitem', + 'aria-selected': 'false' + }; + + if (data.disabled) { + delete attrs['aria-selected']; + attrs['aria-disabled'] = 'true'; + } + + if (data.id == null) { + delete attrs['aria-selected']; + } + + if (data._resultId != null) { + option.id = data._resultId; + } + + if (data.title) { + option.title = data.title; + } + + if (data.children) { + attrs.role = 'group'; + attrs['aria-label'] = data.text; + delete attrs['aria-selected']; + } + + for (var attr in attrs) { + var val = attrs[attr]; + + option.setAttribute(attr, val); + } + + if (data.children) { + var $option = $(option); + + var label = document.createElement('strong'); + label.className = 'select2-results__group'; + + var $label = $(label); + this.template(data, label); + + var $children = []; + + for (var c = 0; c < data.children.length; c++) { + var child = data.children[c]; + + var $child = this.option(child); + + $children.push($child); + } + + var $childrenContainer = $('
      ', { + 'class': 'select2-results__options select2-results__options--nested' + }); + + $childrenContainer.append($children); + + $option.append(label); + $option.append($childrenContainer); + } else { + this.template(data, option); + } + + $.data(option, 'data', data); + + return option; + }; + + Results.prototype.bind = function (container, $container) { + var self = this; + + var id = container.id + '-results'; + + this.$results.attr('id', id); + + container.on('results:all', function (params) { + self.clear(); + self.append(params.data); + + if (container.isOpen()) { + self.setClasses(); + self.highlightFirstItem(); + } + }); + + container.on('results:append', function (params) { + self.append(params.data); + + if (container.isOpen()) { + self.setClasses(); + } + }); + + container.on('query', function (params) { + self.hideMessages(); + self.showLoading(params); + }); + + container.on('select', function () { + if (!container.isOpen()) { + return; + } + + self.setClasses(); + self.highlightFirstItem(); + }); + + container.on('unselect', function () { + if (!container.isOpen()) { + return; + } + + self.setClasses(); + self.highlightFirstItem(); + }); + + container.on('open', function () { + // When the dropdown is open, aria-expended="true" + self.$results.attr('aria-expanded', 'true'); + self.$results.attr('aria-hidden', 'false'); + + self.setClasses(); + self.ensureHighlightVisible(); + }); + + container.on('close', function () { + // When the dropdown is closed, aria-expended="false" + self.$results.attr('aria-expanded', 'false'); + self.$results.attr('aria-hidden', 'true'); + self.$results.removeAttr('aria-activedescendant'); + }); + + container.on('results:toggle', function () { + var $highlighted = self.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + $highlighted.trigger('mouseup'); + }); + + container.on('results:select', function () { + var $highlighted = self.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + var data = $highlighted.data('data'); + + if ($highlighted.attr('aria-selected') == 'true') { + self.trigger('close', {}); + } else { + self.trigger('select', { + data: data + }); + } + }); + + container.on('results:previous', function () { + var $highlighted = self.getHighlightedResults(); + + var $options = self.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + // If we are already at te top, don't move further + if (currentIndex === 0) { + return; + } + + var nextIndex = currentIndex - 1; + + // If none are highlighted, highlight the first + if ($highlighted.length === 0) { + nextIndex = 0; + } + + var $next = $options.eq(nextIndex); + + $next.trigger('mouseenter'); + + var currentOffset = self.$results.offset().top; + var nextTop = $next.offset().top; + var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset); + + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextTop - currentOffset < 0) { + self.$results.scrollTop(nextOffset); + } + }); + + container.on('results:next', function () { + var $highlighted = self.getHighlightedResults(); + + var $options = self.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + var nextIndex = currentIndex + 1; + + // If we are at the last option, stay there + if (nextIndex >= $options.length) { + return; + } + + var $next = $options.eq(nextIndex); + + $next.trigger('mouseenter'); + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var nextBottom = $next.offset().top + $next.outerHeight(false); + var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset; + + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextBottom > currentOffset) { + self.$results.scrollTop(nextOffset); + } + }); + + container.on('results:focus', function (params) { + params.element.addClass('select2-results__option--highlighted'); + }); + + container.on('results:message', function (params) { + self.displayMessage(params); + }); + + if ($.fn.mousewheel) { + this.$results.on('mousewheel', function (e) { + var top = self.$results.scrollTop(); + + var bottom = self.$results.get(0).scrollHeight - top + e.deltaY; + + var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0; + var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height(); + + if (isAtTop) { + self.$results.scrollTop(0); + + e.preventDefault(); + e.stopPropagation(); + } else if (isAtBottom) { + self.$results.scrollTop( + self.$results.get(0).scrollHeight - self.$results.height() + ); + + e.preventDefault(); + e.stopPropagation(); + } + }); + } + + this.$results.on('mouseup', '.select2-results__option[aria-selected]', + function (evt) { + var $this = $(this); + + var data = $this.data('data'); + + if ($this.attr('aria-selected') === 'true') { + if (self.options.get('multiple')) { + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } else { + self.trigger('close', {}); + } + + return; + } + + self.trigger('select', { + originalEvent: evt, + data: data + }); + }); + + this.$results.on('mouseenter', '.select2-results__option[aria-selected]', + function (evt) { + var data = $(this).data('data'); + + self.getHighlightedResults() + .removeClass('select2-results__option--highlighted'); + + self.trigger('results:focus', { + data: data, + element: $(this) + }); + }); + }; + + Results.prototype.getHighlightedResults = function () { + var $highlighted = this.$results + .find('.select2-results__option--highlighted'); + + return $highlighted; + }; + + Results.prototype.destroy = function () { + this.$results.remove(); + }; + + Results.prototype.ensureHighlightVisible = function () { + var $highlighted = this.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + var $options = this.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + var currentOffset = this.$results.offset().top; + var nextTop = $highlighted.offset().top; + var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset); + + var offsetDelta = nextTop - currentOffset; + nextOffset -= $highlighted.outerHeight(false) * 2; + + if (currentIndex <= 2) { + this.$results.scrollTop(0); + } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) { + this.$results.scrollTop(nextOffset); + } + }; + + Results.prototype.template = function (result, container) { + var template = this.options.get('templateResult'); + var escapeMarkup = this.options.get('escapeMarkup'); + + var content = template(result, container); + + if (content == null) { + container.style.display = 'none'; + } else if (typeof content === 'string') { + container.innerHTML = escapeMarkup(content); + } else { + $(container).append(content); + } + }; + + return Results; +}); + +S2.define('select2/keys',[ + +], function () { + var KEYS = { + BACKSPACE: 8, + TAB: 9, + ENTER: 13, + SHIFT: 16, + CTRL: 17, + ALT: 18, + ESC: 27, + SPACE: 32, + PAGE_UP: 33, + PAGE_DOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + DELETE: 46 + }; + + return KEYS; +}); + +S2.define('select2/selection/base',[ + 'jquery', + '../utils', + '../keys' +], function ($, Utils, KEYS) { + function BaseSelection ($element, options) { + this.$element = $element; + this.options = options; + + BaseSelection.__super__.constructor.call(this); + } + + Utils.Extend(BaseSelection, Utils.Observable); + + BaseSelection.prototype.render = function () { + var $selection = $( + '' + ); + + this._tabindex = 0; + + if (this.$element.data('old-tabindex') != null) { + this._tabindex = this.$element.data('old-tabindex'); + } else if (this.$element.attr('tabindex') != null) { + this._tabindex = this.$element.attr('tabindex'); + } + + $selection.attr('title', this.$element.attr('title')); + $selection.attr('tabindex', this._tabindex); + + this.$selection = $selection; + + return $selection; + }; + + BaseSelection.prototype.bind = function (container, $container) { + var self = this; + + var id = container.id + '-container'; + var resultsId = container.id + '-results'; + + this.container = container; + + this.$selection.on('focus', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('blur', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', function (evt) { + self.trigger('keypress', evt); + + if (evt.which === KEYS.SPACE) { + evt.preventDefault(); + } + }); + + container.on('results:focus', function (params) { + self.$selection.attr('aria-activedescendant', params.data._resultId); + }); + + container.on('selection:update', function (params) { + self.update(params.data); + }); + + container.on('open', function () { + // When the dropdown is open, aria-expanded="true" + self.$selection.attr('aria-expanded', 'true'); + self.$selection.attr('aria-owns', resultsId); + + self._attachCloseHandler(container); + }); + + container.on('close', function () { + // When the dropdown is closed, aria-expanded="false" + self.$selection.attr('aria-expanded', 'false'); + self.$selection.removeAttr('aria-activedescendant'); + self.$selection.removeAttr('aria-owns'); + + self.$selection.focus(); + + self._detachCloseHandler(container); + }); + + container.on('enable', function () { + self.$selection.attr('tabindex', self._tabindex); + }); + + container.on('disable', function () { + self.$selection.attr('tabindex', '-1'); + }); + }; + + BaseSelection.prototype._handleBlur = function (evt) { + var self = this; + + // This needs to be delayed as the active element is the body when the tab + // key is pressed, possibly along with others. + window.setTimeout(function () { + // Don't trigger `blur` if the focus is still in the selection + if ( + (document.activeElement == self.$selection[0]) || + ($.contains(self.$selection[0], document.activeElement)) + ) { + return; + } + + self.trigger('blur', evt); + }, 1); + }; + + BaseSelection.prototype._attachCloseHandler = function (container) { + var self = this; + + $(document.body).on('mousedown.select2.' + container.id, function (e) { + var $target = $(e.target); + + var $select = $target.closest('.select2'); + + var $all = $('.select2.select2-container--open'); + + $all.each(function () { + var $this = $(this); + + if (this == $select[0]) { + return; + } + + var $element = $this.data('element'); + + $element.select2('close'); + }); + }); + }; + + BaseSelection.prototype._detachCloseHandler = function (container) { + $(document.body).off('mousedown.select2.' + container.id); + }; + + BaseSelection.prototype.position = function ($selection, $container) { + var $selectionContainer = $container.find('.selection'); + $selectionContainer.append($selection); + }; + + BaseSelection.prototype.destroy = function () { + this._detachCloseHandler(this.container); + }; + + BaseSelection.prototype.update = function (data) { + throw new Error('The `update` method must be defined in child classes.'); + }; + + return BaseSelection; +}); + +S2.define('select2/selection/single',[ + 'jquery', + './base', + '../utils', + '../keys' +], function ($, BaseSelection, Utils, KEYS) { + function SingleSelection () { + SingleSelection.__super__.constructor.apply(this, arguments); + } + + Utils.Extend(SingleSelection, BaseSelection); + + SingleSelection.prototype.render = function () { + var $selection = SingleSelection.__super__.render.call(this); + + $selection.addClass('select2-selection--single'); + + $selection.html( + '' + + '' + + '' + + '' + ); + + return $selection; + }; + + SingleSelection.prototype.bind = function (container, $container) { + var self = this; + + SingleSelection.__super__.bind.apply(this, arguments); + + var id = container.id + '-container'; + + this.$selection.find('.select2-selection__rendered').attr('id', id); + this.$selection.attr('aria-labelledby', id); + + this.$selection.on('mousedown', function (evt) { + // Only respond to left clicks + if (evt.which !== 1) { + return; + } + + self.trigger('toggle', { + originalEvent: evt + }); + }); + + this.$selection.on('focus', function (evt) { + // User focuses on the container + }); + + this.$selection.on('blur', function (evt) { + // User exits the container + }); + + container.on('focus', function (evt) { + if (!container.isOpen()) { + self.$selection.focus(); + } + }); + + container.on('selection:update', function (params) { + self.update(params.data); + }); + }; + + SingleSelection.prototype.clear = function () { + this.$selection.find('.select2-selection__rendered').empty(); + }; + + SingleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); + + return escapeMarkup(template(data, container)); + }; + + SingleSelection.prototype.selectionContainer = function () { + return $(''); + }; + + SingleSelection.prototype.update = function (data) { + if (data.length === 0) { + this.clear(); + return; + } + + var selection = data[0]; + + var $rendered = this.$selection.find('.select2-selection__rendered'); + var formatted = this.display(selection, $rendered); + + $rendered.empty().append(formatted); + $rendered.prop('title', selection.title || selection.text); + }; + + return SingleSelection; +}); + +S2.define('select2/selection/multiple',[ + 'jquery', + './base', + '../utils' +], function ($, BaseSelection, Utils) { + function MultipleSelection ($element, options) { + MultipleSelection.__super__.constructor.apply(this, arguments); + } + + Utils.Extend(MultipleSelection, BaseSelection); + + MultipleSelection.prototype.render = function () { + var $selection = MultipleSelection.__super__.render.call(this); + + $selection.addClass('select2-selection--multiple'); + + $selection.html( + '
        ' + ); + + return $selection; + }; + + MultipleSelection.prototype.bind = function (container, $container) { + var self = this; + + MultipleSelection.__super__.bind.apply(this, arguments); + + this.$selection.on('click', function (evt) { + self.trigger('toggle', { + originalEvent: evt + }); + }); + + this.$selection.on( + 'click', + '.select2-selection__choice__remove', + function (evt) { + // Ignore the event if it is disabled + if (self.options.get('disabled')) { + return; + } + + var $remove = $(this); + var $selection = $remove.parent(); + + var data = $selection.data('data'); + + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } + ); + }; + + MultipleSelection.prototype.clear = function () { + this.$selection.find('.select2-selection__rendered').empty(); + }; + + MultipleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); + + return escapeMarkup(template(data, container)); + }; + + MultipleSelection.prototype.selectionContainer = function () { + var $container = $( + '
      • ' + + '' + + '×' + + '' + + '
      • ' + ); + + return $container; + }; + + MultipleSelection.prototype.update = function (data) { + this.clear(); + + if (data.length === 0) { + return; + } + + var $selections = []; + + for (var d = 0; d < data.length; d++) { + var selection = data[d]; + + var $selection = this.selectionContainer(); + var formatted = this.display(selection, $selection); + + $selection.append(formatted); + $selection.prop('title', selection.title || selection.text); + + $selection.data('data', selection); + + $selections.push($selection); + } + + var $rendered = this.$selection.find('.select2-selection__rendered'); + + Utils.appendMany($rendered, $selections); + }; + + return MultipleSelection; +}); + +S2.define('select2/selection/placeholder',[ + '../utils' +], function (Utils) { + function Placeholder (decorated, $element, options) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options); + } + + Placeholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + Placeholder.prototype.createPlaceholder = function (decorated, placeholder) { + var $placeholder = this.selectionContainer(); + + $placeholder.html(this.display(placeholder)); + $placeholder.addClass('select2-selection__placeholder') + .removeClass('select2-selection__choice'); + + return $placeholder; + }; + + Placeholder.prototype.update = function (decorated, data) { + var singlePlaceholder = ( + data.length == 1 && data[0].id != this.placeholder.id + ); + var multipleSelections = data.length > 1; + + if (multipleSelections || singlePlaceholder) { + return decorated.call(this, data); + } + + this.clear(); + + var $placeholder = this.createPlaceholder(this.placeholder); + + this.$selection.find('.select2-selection__rendered').append($placeholder); + }; + + return Placeholder; +}); + +S2.define('select2/selection/allowClear',[ + 'jquery', + '../keys' +], function ($, KEYS) { + function AllowClear () { } + + AllowClear.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + if (this.placeholder == null) { + if (this.options.get('debug') && window.console && console.error) { + console.error( + 'Select2: The `allowClear` option should be used in combination ' + + 'with the `placeholder` option.' + ); + } + } + + this.$selection.on('mousedown', '.select2-selection__clear', + function (evt) { + self._handleClear(evt); + }); + + container.on('keypress', function (evt) { + self._handleKeyboardClear(evt, container); + }); + }; + + AllowClear.prototype._handleClear = function (_, evt) { + // Ignore the event if it is disabled + if (this.options.get('disabled')) { + return; + } + + var $clear = this.$selection.find('.select2-selection__clear'); + + // Ignore the event if nothing has been selected + if ($clear.length === 0) { + return; + } + + evt.stopPropagation(); + + var data = $clear.data('data'); + + for (var d = 0; d < data.length; d++) { + var unselectData = { + data: data[d] + }; + + // Trigger the `unselect` event, so people can prevent it from being + // cleared. + this.trigger('unselect', unselectData); + + // If the event was prevented, don't clear it out. + if (unselectData.prevented) { + return; + } + } + + this.$element.val(this.placeholder.id).trigger('change'); + + this.trigger('toggle', {}); + }; + + AllowClear.prototype._handleKeyboardClear = function (_, evt, container) { + if (container.isOpen()) { + return; + } + + if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) { + this._handleClear(evt); + } + }; + + AllowClear.prototype.update = function (decorated, data) { + decorated.call(this, data); + + if (this.$selection.find('.select2-selection__placeholder').length > 0 || + data.length === 0) { + return; + } + + var $remove = $( + '' + + '×' + + '' + ); + $remove.data('data', data); + + this.$selection.find('.select2-selection__rendered').prepend($remove); + }; + + return AllowClear; +}); + +S2.define('select2/selection/search',[ + 'jquery', + '../utils', + '../keys' +], function ($, Utils, KEYS) { + function Search (decorated, $element, options) { + decorated.call(this, $element, options); + } + + Search.prototype.render = function (decorated) { + var $search = $( + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + var $rendered = decorated.call(this); + + this._transferTabIndex(); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('open', function () { + self.$search.trigger('focus'); + }); + + container.on('close', function () { + self.$search.val(''); + self.$search.removeAttr('aria-activedescendant'); + self.$search.trigger('focus'); + }); + + container.on('enable', function () { + self.$search.prop('disabled', false); + + self._transferTabIndex(); + }); + + container.on('disable', function () { + self.$search.prop('disabled', true); + }); + + container.on('focus', function (evt) { + self.$search.trigger('focus'); + }); + + container.on('results:focus', function (params) { + self.$search.attr('aria-activedescendant', params.id); + }); + + this.$selection.on('focusin', '.select2-search--inline', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('focusout', '.select2-search--inline', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', '.select2-search--inline', function (evt) { + evt.stopPropagation(); + + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + + var key = evt.which; + + if (key === KEYS.BACKSPACE && self.$search.val() === '') { + var $previousChoice = self.$searchContainer + .prev('.select2-selection__choice'); + + if ($previousChoice.length > 0) { + var item = $previousChoice.data('data'); + + self.searchRemoveChoice(item); + + evt.preventDefault(); + } + } + }); + + // Try to detect the IE version should the `documentMode` property that + // is stored on the document. This is only implemented in IE and is + // slightly cleaner than doing a user agent check. + // This property is not available in Edge, but Edge also doesn't have + // this bug. + var msie = document.documentMode; + var disableInputEvents = msie && msie <= 11; + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$selection.on( + 'input.searchcheck', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents) { + self.$selection.off('input.search input.searchcheck'); + return; + } + + // Unbind the duplicated `keyup` event + self.$selection.off('keyup.search'); + } + ); + + this.$selection.on( + 'keyup.search input.search', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents && evt.type === 'input') { + self.$selection.off('input.search input.searchcheck'); + return; + } + + var key = evt.which; + + // We can freely ignore events from modifier keys + if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) { + return; + } + + // Tabbing will be handled during the `keydown` phase + if (key == KEYS.TAB) { + return; + } + + self.handleSearch(evt); + } + ); + }; + + /** + * This method will transfer the tabindex attribute from the rendered + * selection to the search box. This allows for the search box to be used as + * the primary focus instead of the selection container. + * + * @private + */ + Search.prototype._transferTabIndex = function (decorated) { + this.$search.attr('tabindex', this.$selection.attr('tabindex')); + this.$selection.attr('tabindex', '-1'); + }; + + Search.prototype.createPlaceholder = function (decorated, placeholder) { + this.$search.attr('placeholder', placeholder.text); + }; + + Search.prototype.update = function (decorated, data) { + var searchHadFocus = this.$search[0] == document.activeElement; + + this.$search.attr('placeholder', ''); + + decorated.call(this, data); + + this.$selection.find('.select2-selection__rendered') + .append(this.$searchContainer); + + this.resizeSearch(); + if (searchHadFocus) { + this.$search.focus(); + } + }; + + Search.prototype.handleSearch = function () { + this.resizeSearch(); + + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.searchRemoveChoice = function (decorated, item) { + this.trigger('unselect', { + data: item + }); + + this.$search.val(item.text); + this.handleSearch(); + }; + + Search.prototype.resizeSearch = function () { + this.$search.css('width', '25px'); + + var width = ''; + + if (this.$search.attr('placeholder') !== '') { + width = this.$selection.find('.select2-selection__rendered').innerWidth(); + } else { + var minimumWidth = this.$search.val().length + 1; + + width = (minimumWidth * 0.75) + 'em'; + } + + this.$search.css('width', width); + }; + + return Search; +}); + +S2.define('select2/selection/eventRelay',[ + 'jquery' +], function ($) { + function EventRelay () { } + + EventRelay.prototype.bind = function (decorated, container, $container) { + var self = this; + var relayEvents = [ + 'open', 'opening', + 'close', 'closing', + 'select', 'selecting', + 'unselect', 'unselecting' + ]; + + var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; + + decorated.call(this, container, $container); + + container.on('*', function (name, params) { + // Ignore events that should not be relayed + if ($.inArray(name, relayEvents) === -1) { + return; + } + + // The parameters should always be an object + params = params || {}; + + // Generate the jQuery event for the Select2 event + var evt = $.Event('select2:' + name, { + params: params + }); + + self.$element.trigger(evt); + + // Only handle preventable events if it was one + if ($.inArray(name, preventableEvents) === -1) { + return; + } + + params.prevented = evt.isDefaultPrevented(); + }); + }; + + return EventRelay; +}); + +S2.define('select2/translation',[ + 'jquery', + 'require' +], function ($, require) { + function Translation (dict) { + this.dict = dict || {}; + } + + Translation.prototype.all = function () { + return this.dict; + }; + + Translation.prototype.get = function (key) { + return this.dict[key]; + }; + + Translation.prototype.extend = function (translation) { + this.dict = $.extend({}, translation.all(), this.dict); + }; + + // Static functions + + Translation._cache = {}; + + Translation.loadPath = function (path) { + if (!(path in Translation._cache)) { + var translations = require(path); + + Translation._cache[path] = translations; + } + + return new Translation(Translation._cache[path]); + }; + + return Translation; +}); + +S2.define('select2/diacritics',[ + +], function () { + var diacritics = { + '\u24B6': 'A', + '\uFF21': 'A', + '\u00C0': 'A', + '\u00C1': 'A', + '\u00C2': 'A', + '\u1EA6': 'A', + '\u1EA4': 'A', + '\u1EAA': 'A', + '\u1EA8': 'A', + '\u00C3': 'A', + '\u0100': 'A', + '\u0102': 'A', + '\u1EB0': 'A', + '\u1EAE': 'A', + '\u1EB4': 'A', + '\u1EB2': 'A', + '\u0226': 'A', + '\u01E0': 'A', + '\u00C4': 'A', + '\u01DE': 'A', + '\u1EA2': 'A', + '\u00C5': 'A', + '\u01FA': 'A', + '\u01CD': 'A', + '\u0200': 'A', + '\u0202': 'A', + '\u1EA0': 'A', + '\u1EAC': 'A', + '\u1EB6': 'A', + '\u1E00': 'A', + '\u0104': 'A', + '\u023A': 'A', + '\u2C6F': 'A', + '\uA732': 'AA', + '\u00C6': 'AE', + '\u01FC': 'AE', + '\u01E2': 'AE', + '\uA734': 'AO', + '\uA736': 'AU', + '\uA738': 'AV', + '\uA73A': 'AV', + '\uA73C': 'AY', + '\u24B7': 'B', + '\uFF22': 'B', + '\u1E02': 'B', + '\u1E04': 'B', + '\u1E06': 'B', + '\u0243': 'B', + '\u0182': 'B', + '\u0181': 'B', + '\u24B8': 'C', + '\uFF23': 'C', + '\u0106': 'C', + '\u0108': 'C', + '\u010A': 'C', + '\u010C': 'C', + '\u00C7': 'C', + '\u1E08': 'C', + '\u0187': 'C', + '\u023B': 'C', + '\uA73E': 'C', + '\u24B9': 'D', + '\uFF24': 'D', + '\u1E0A': 'D', + '\u010E': 'D', + '\u1E0C': 'D', + '\u1E10': 'D', + '\u1E12': 'D', + '\u1E0E': 'D', + '\u0110': 'D', + '\u018B': 'D', + '\u018A': 'D', + '\u0189': 'D', + '\uA779': 'D', + '\u01F1': 'DZ', + '\u01C4': 'DZ', + '\u01F2': 'Dz', + '\u01C5': 'Dz', + '\u24BA': 'E', + '\uFF25': 'E', + '\u00C8': 'E', + '\u00C9': 'E', + '\u00CA': 'E', + '\u1EC0': 'E', + '\u1EBE': 'E', + '\u1EC4': 'E', + '\u1EC2': 'E', + '\u1EBC': 'E', + '\u0112': 'E', + '\u1E14': 'E', + '\u1E16': 'E', + '\u0114': 'E', + '\u0116': 'E', + '\u00CB': 'E', + '\u1EBA': 'E', + '\u011A': 'E', + '\u0204': 'E', + '\u0206': 'E', + '\u1EB8': 'E', + '\u1EC6': 'E', + '\u0228': 'E', + '\u1E1C': 'E', + '\u0118': 'E', + '\u1E18': 'E', + '\u1E1A': 'E', + '\u0190': 'E', + '\u018E': 'E', + '\u24BB': 'F', + '\uFF26': 'F', + '\u1E1E': 'F', + '\u0191': 'F', + '\uA77B': 'F', + '\u24BC': 'G', + '\uFF27': 'G', + '\u01F4': 'G', + '\u011C': 'G', + '\u1E20': 'G', + '\u011E': 'G', + '\u0120': 'G', + '\u01E6': 'G', + '\u0122': 'G', + '\u01E4': 'G', + '\u0193': 'G', + '\uA7A0': 'G', + '\uA77D': 'G', + '\uA77E': 'G', + '\u24BD': 'H', + '\uFF28': 'H', + '\u0124': 'H', + '\u1E22': 'H', + '\u1E26': 'H', + '\u021E': 'H', + '\u1E24': 'H', + '\u1E28': 'H', + '\u1E2A': 'H', + '\u0126': 'H', + '\u2C67': 'H', + '\u2C75': 'H', + '\uA78D': 'H', + '\u24BE': 'I', + '\uFF29': 'I', + '\u00CC': 'I', + '\u00CD': 'I', + '\u00CE': 'I', + '\u0128': 'I', + '\u012A': 'I', + '\u012C': 'I', + '\u0130': 'I', + '\u00CF': 'I', + '\u1E2E': 'I', + '\u1EC8': 'I', + '\u01CF': 'I', + '\u0208': 'I', + '\u020A': 'I', + '\u1ECA': 'I', + '\u012E': 'I', + '\u1E2C': 'I', + '\u0197': 'I', + '\u24BF': 'J', + '\uFF2A': 'J', + '\u0134': 'J', + '\u0248': 'J', + '\u24C0': 'K', + '\uFF2B': 'K', + '\u1E30': 'K', + '\u01E8': 'K', + '\u1E32': 'K', + '\u0136': 'K', + '\u1E34': 'K', + '\u0198': 'K', + '\u2C69': 'K', + '\uA740': 'K', + '\uA742': 'K', + '\uA744': 'K', + '\uA7A2': 'K', + '\u24C1': 'L', + '\uFF2C': 'L', + '\u013F': 'L', + '\u0139': 'L', + '\u013D': 'L', + '\u1E36': 'L', + '\u1E38': 'L', + '\u013B': 'L', + '\u1E3C': 'L', + '\u1E3A': 'L', + '\u0141': 'L', + '\u023D': 'L', + '\u2C62': 'L', + '\u2C60': 'L', + '\uA748': 'L', + '\uA746': 'L', + '\uA780': 'L', + '\u01C7': 'LJ', + '\u01C8': 'Lj', + '\u24C2': 'M', + '\uFF2D': 'M', + '\u1E3E': 'M', + '\u1E40': 'M', + '\u1E42': 'M', + '\u2C6E': 'M', + '\u019C': 'M', + '\u24C3': 'N', + '\uFF2E': 'N', + '\u01F8': 'N', + '\u0143': 'N', + '\u00D1': 'N', + '\u1E44': 'N', + '\u0147': 'N', + '\u1E46': 'N', + '\u0145': 'N', + '\u1E4A': 'N', + '\u1E48': 'N', + '\u0220': 'N', + '\u019D': 'N', + '\uA790': 'N', + '\uA7A4': 'N', + '\u01CA': 'NJ', + '\u01CB': 'Nj', + '\u24C4': 'O', + '\uFF2F': 'O', + '\u00D2': 'O', + '\u00D3': 'O', + '\u00D4': 'O', + '\u1ED2': 'O', + '\u1ED0': 'O', + '\u1ED6': 'O', + '\u1ED4': 'O', + '\u00D5': 'O', + '\u1E4C': 'O', + '\u022C': 'O', + '\u1E4E': 'O', + '\u014C': 'O', + '\u1E50': 'O', + '\u1E52': 'O', + '\u014E': 'O', + '\u022E': 'O', + '\u0230': 'O', + '\u00D6': 'O', + '\u022A': 'O', + '\u1ECE': 'O', + '\u0150': 'O', + '\u01D1': 'O', + '\u020C': 'O', + '\u020E': 'O', + '\u01A0': 'O', + '\u1EDC': 'O', + '\u1EDA': 'O', + '\u1EE0': 'O', + '\u1EDE': 'O', + '\u1EE2': 'O', + '\u1ECC': 'O', + '\u1ED8': 'O', + '\u01EA': 'O', + '\u01EC': 'O', + '\u00D8': 'O', + '\u01FE': 'O', + '\u0186': 'O', + '\u019F': 'O', + '\uA74A': 'O', + '\uA74C': 'O', + '\u01A2': 'OI', + '\uA74E': 'OO', + '\u0222': 'OU', + '\u24C5': 'P', + '\uFF30': 'P', + '\u1E54': 'P', + '\u1E56': 'P', + '\u01A4': 'P', + '\u2C63': 'P', + '\uA750': 'P', + '\uA752': 'P', + '\uA754': 'P', + '\u24C6': 'Q', + '\uFF31': 'Q', + '\uA756': 'Q', + '\uA758': 'Q', + '\u024A': 'Q', + '\u24C7': 'R', + '\uFF32': 'R', + '\u0154': 'R', + '\u1E58': 'R', + '\u0158': 'R', + '\u0210': 'R', + '\u0212': 'R', + '\u1E5A': 'R', + '\u1E5C': 'R', + '\u0156': 'R', + '\u1E5E': 'R', + '\u024C': 'R', + '\u2C64': 'R', + '\uA75A': 'R', + '\uA7A6': 'R', + '\uA782': 'R', + '\u24C8': 'S', + '\uFF33': 'S', + '\u1E9E': 'S', + '\u015A': 'S', + '\u1E64': 'S', + '\u015C': 'S', + '\u1E60': 'S', + '\u0160': 'S', + '\u1E66': 'S', + '\u1E62': 'S', + '\u1E68': 'S', + '\u0218': 'S', + '\u015E': 'S', + '\u2C7E': 'S', + '\uA7A8': 'S', + '\uA784': 'S', + '\u24C9': 'T', + '\uFF34': 'T', + '\u1E6A': 'T', + '\u0164': 'T', + '\u1E6C': 'T', + '\u021A': 'T', + '\u0162': 'T', + '\u1E70': 'T', + '\u1E6E': 'T', + '\u0166': 'T', + '\u01AC': 'T', + '\u01AE': 'T', + '\u023E': 'T', + '\uA786': 'T', + '\uA728': 'TZ', + '\u24CA': 'U', + '\uFF35': 'U', + '\u00D9': 'U', + '\u00DA': 'U', + '\u00DB': 'U', + '\u0168': 'U', + '\u1E78': 'U', + '\u016A': 'U', + '\u1E7A': 'U', + '\u016C': 'U', + '\u00DC': 'U', + '\u01DB': 'U', + '\u01D7': 'U', + '\u01D5': 'U', + '\u01D9': 'U', + '\u1EE6': 'U', + '\u016E': 'U', + '\u0170': 'U', + '\u01D3': 'U', + '\u0214': 'U', + '\u0216': 'U', + '\u01AF': 'U', + '\u1EEA': 'U', + '\u1EE8': 'U', + '\u1EEE': 'U', + '\u1EEC': 'U', + '\u1EF0': 'U', + '\u1EE4': 'U', + '\u1E72': 'U', + '\u0172': 'U', + '\u1E76': 'U', + '\u1E74': 'U', + '\u0244': 'U', + '\u24CB': 'V', + '\uFF36': 'V', + '\u1E7C': 'V', + '\u1E7E': 'V', + '\u01B2': 'V', + '\uA75E': 'V', + '\u0245': 'V', + '\uA760': 'VY', + '\u24CC': 'W', + '\uFF37': 'W', + '\u1E80': 'W', + '\u1E82': 'W', + '\u0174': 'W', + '\u1E86': 'W', + '\u1E84': 'W', + '\u1E88': 'W', + '\u2C72': 'W', + '\u24CD': 'X', + '\uFF38': 'X', + '\u1E8A': 'X', + '\u1E8C': 'X', + '\u24CE': 'Y', + '\uFF39': 'Y', + '\u1EF2': 'Y', + '\u00DD': 'Y', + '\u0176': 'Y', + '\u1EF8': 'Y', + '\u0232': 'Y', + '\u1E8E': 'Y', + '\u0178': 'Y', + '\u1EF6': 'Y', + '\u1EF4': 'Y', + '\u01B3': 'Y', + '\u024E': 'Y', + '\u1EFE': 'Y', + '\u24CF': 'Z', + '\uFF3A': 'Z', + '\u0179': 'Z', + '\u1E90': 'Z', + '\u017B': 'Z', + '\u017D': 'Z', + '\u1E92': 'Z', + '\u1E94': 'Z', + '\u01B5': 'Z', + '\u0224': 'Z', + '\u2C7F': 'Z', + '\u2C6B': 'Z', + '\uA762': 'Z', + '\u24D0': 'a', + '\uFF41': 'a', + '\u1E9A': 'a', + '\u00E0': 'a', + '\u00E1': 'a', + '\u00E2': 'a', + '\u1EA7': 'a', + '\u1EA5': 'a', + '\u1EAB': 'a', + '\u1EA9': 'a', + '\u00E3': 'a', + '\u0101': 'a', + '\u0103': 'a', + '\u1EB1': 'a', + '\u1EAF': 'a', + '\u1EB5': 'a', + '\u1EB3': 'a', + '\u0227': 'a', + '\u01E1': 'a', + '\u00E4': 'a', + '\u01DF': 'a', + '\u1EA3': 'a', + '\u00E5': 'a', + '\u01FB': 'a', + '\u01CE': 'a', + '\u0201': 'a', + '\u0203': 'a', + '\u1EA1': 'a', + '\u1EAD': 'a', + '\u1EB7': 'a', + '\u1E01': 'a', + '\u0105': 'a', + '\u2C65': 'a', + '\u0250': 'a', + '\uA733': 'aa', + '\u00E6': 'ae', + '\u01FD': 'ae', + '\u01E3': 'ae', + '\uA735': 'ao', + '\uA737': 'au', + '\uA739': 'av', + '\uA73B': 'av', + '\uA73D': 'ay', + '\u24D1': 'b', + '\uFF42': 'b', + '\u1E03': 'b', + '\u1E05': 'b', + '\u1E07': 'b', + '\u0180': 'b', + '\u0183': 'b', + '\u0253': 'b', + '\u24D2': 'c', + '\uFF43': 'c', + '\u0107': 'c', + '\u0109': 'c', + '\u010B': 'c', + '\u010D': 'c', + '\u00E7': 'c', + '\u1E09': 'c', + '\u0188': 'c', + '\u023C': 'c', + '\uA73F': 'c', + '\u2184': 'c', + '\u24D3': 'd', + '\uFF44': 'd', + '\u1E0B': 'd', + '\u010F': 'd', + '\u1E0D': 'd', + '\u1E11': 'd', + '\u1E13': 'd', + '\u1E0F': 'd', + '\u0111': 'd', + '\u018C': 'd', + '\u0256': 'd', + '\u0257': 'd', + '\uA77A': 'd', + '\u01F3': 'dz', + '\u01C6': 'dz', + '\u24D4': 'e', + '\uFF45': 'e', + '\u00E8': 'e', + '\u00E9': 'e', + '\u00EA': 'e', + '\u1EC1': 'e', + '\u1EBF': 'e', + '\u1EC5': 'e', + '\u1EC3': 'e', + '\u1EBD': 'e', + '\u0113': 'e', + '\u1E15': 'e', + '\u1E17': 'e', + '\u0115': 'e', + '\u0117': 'e', + '\u00EB': 'e', + '\u1EBB': 'e', + '\u011B': 'e', + '\u0205': 'e', + '\u0207': 'e', + '\u1EB9': 'e', + '\u1EC7': 'e', + '\u0229': 'e', + '\u1E1D': 'e', + '\u0119': 'e', + '\u1E19': 'e', + '\u1E1B': 'e', + '\u0247': 'e', + '\u025B': 'e', + '\u01DD': 'e', + '\u24D5': 'f', + '\uFF46': 'f', + '\u1E1F': 'f', + '\u0192': 'f', + '\uA77C': 'f', + '\u24D6': 'g', + '\uFF47': 'g', + '\u01F5': 'g', + '\u011D': 'g', + '\u1E21': 'g', + '\u011F': 'g', + '\u0121': 'g', + '\u01E7': 'g', + '\u0123': 'g', + '\u01E5': 'g', + '\u0260': 'g', + '\uA7A1': 'g', + '\u1D79': 'g', + '\uA77F': 'g', + '\u24D7': 'h', + '\uFF48': 'h', + '\u0125': 'h', + '\u1E23': 'h', + '\u1E27': 'h', + '\u021F': 'h', + '\u1E25': 'h', + '\u1E29': 'h', + '\u1E2B': 'h', + '\u1E96': 'h', + '\u0127': 'h', + '\u2C68': 'h', + '\u2C76': 'h', + '\u0265': 'h', + '\u0195': 'hv', + '\u24D8': 'i', + '\uFF49': 'i', + '\u00EC': 'i', + '\u00ED': 'i', + '\u00EE': 'i', + '\u0129': 'i', + '\u012B': 'i', + '\u012D': 'i', + '\u00EF': 'i', + '\u1E2F': 'i', + '\u1EC9': 'i', + '\u01D0': 'i', + '\u0209': 'i', + '\u020B': 'i', + '\u1ECB': 'i', + '\u012F': 'i', + '\u1E2D': 'i', + '\u0268': 'i', + '\u0131': 'i', + '\u24D9': 'j', + '\uFF4A': 'j', + '\u0135': 'j', + '\u01F0': 'j', + '\u0249': 'j', + '\u24DA': 'k', + '\uFF4B': 'k', + '\u1E31': 'k', + '\u01E9': 'k', + '\u1E33': 'k', + '\u0137': 'k', + '\u1E35': 'k', + '\u0199': 'k', + '\u2C6A': 'k', + '\uA741': 'k', + '\uA743': 'k', + '\uA745': 'k', + '\uA7A3': 'k', + '\u24DB': 'l', + '\uFF4C': 'l', + '\u0140': 'l', + '\u013A': 'l', + '\u013E': 'l', + '\u1E37': 'l', + '\u1E39': 'l', + '\u013C': 'l', + '\u1E3D': 'l', + '\u1E3B': 'l', + '\u017F': 'l', + '\u0142': 'l', + '\u019A': 'l', + '\u026B': 'l', + '\u2C61': 'l', + '\uA749': 'l', + '\uA781': 'l', + '\uA747': 'l', + '\u01C9': 'lj', + '\u24DC': 'm', + '\uFF4D': 'm', + '\u1E3F': 'm', + '\u1E41': 'm', + '\u1E43': 'm', + '\u0271': 'm', + '\u026F': 'm', + '\u24DD': 'n', + '\uFF4E': 'n', + '\u01F9': 'n', + '\u0144': 'n', + '\u00F1': 'n', + '\u1E45': 'n', + '\u0148': 'n', + '\u1E47': 'n', + '\u0146': 'n', + '\u1E4B': 'n', + '\u1E49': 'n', + '\u019E': 'n', + '\u0272': 'n', + '\u0149': 'n', + '\uA791': 'n', + '\uA7A5': 'n', + '\u01CC': 'nj', + '\u24DE': 'o', + '\uFF4F': 'o', + '\u00F2': 'o', + '\u00F3': 'o', + '\u00F4': 'o', + '\u1ED3': 'o', + '\u1ED1': 'o', + '\u1ED7': 'o', + '\u1ED5': 'o', + '\u00F5': 'o', + '\u1E4D': 'o', + '\u022D': 'o', + '\u1E4F': 'o', + '\u014D': 'o', + '\u1E51': 'o', + '\u1E53': 'o', + '\u014F': 'o', + '\u022F': 'o', + '\u0231': 'o', + '\u00F6': 'o', + '\u022B': 'o', + '\u1ECF': 'o', + '\u0151': 'o', + '\u01D2': 'o', + '\u020D': 'o', + '\u020F': 'o', + '\u01A1': 'o', + '\u1EDD': 'o', + '\u1EDB': 'o', + '\u1EE1': 'o', + '\u1EDF': 'o', + '\u1EE3': 'o', + '\u1ECD': 'o', + '\u1ED9': 'o', + '\u01EB': 'o', + '\u01ED': 'o', + '\u00F8': 'o', + '\u01FF': 'o', + '\u0254': 'o', + '\uA74B': 'o', + '\uA74D': 'o', + '\u0275': 'o', + '\u01A3': 'oi', + '\u0223': 'ou', + '\uA74F': 'oo', + '\u24DF': 'p', + '\uFF50': 'p', + '\u1E55': 'p', + '\u1E57': 'p', + '\u01A5': 'p', + '\u1D7D': 'p', + '\uA751': 'p', + '\uA753': 'p', + '\uA755': 'p', + '\u24E0': 'q', + '\uFF51': 'q', + '\u024B': 'q', + '\uA757': 'q', + '\uA759': 'q', + '\u24E1': 'r', + '\uFF52': 'r', + '\u0155': 'r', + '\u1E59': 'r', + '\u0159': 'r', + '\u0211': 'r', + '\u0213': 'r', + '\u1E5B': 'r', + '\u1E5D': 'r', + '\u0157': 'r', + '\u1E5F': 'r', + '\u024D': 'r', + '\u027D': 'r', + '\uA75B': 'r', + '\uA7A7': 'r', + '\uA783': 'r', + '\u24E2': 's', + '\uFF53': 's', + '\u00DF': 's', + '\u015B': 's', + '\u1E65': 's', + '\u015D': 's', + '\u1E61': 's', + '\u0161': 's', + '\u1E67': 's', + '\u1E63': 's', + '\u1E69': 's', + '\u0219': 's', + '\u015F': 's', + '\u023F': 's', + '\uA7A9': 's', + '\uA785': 's', + '\u1E9B': 's', + '\u24E3': 't', + '\uFF54': 't', + '\u1E6B': 't', + '\u1E97': 't', + '\u0165': 't', + '\u1E6D': 't', + '\u021B': 't', + '\u0163': 't', + '\u1E71': 't', + '\u1E6F': 't', + '\u0167': 't', + '\u01AD': 't', + '\u0288': 't', + '\u2C66': 't', + '\uA787': 't', + '\uA729': 'tz', + '\u24E4': 'u', + '\uFF55': 'u', + '\u00F9': 'u', + '\u00FA': 'u', + '\u00FB': 'u', + '\u0169': 'u', + '\u1E79': 'u', + '\u016B': 'u', + '\u1E7B': 'u', + '\u016D': 'u', + '\u00FC': 'u', + '\u01DC': 'u', + '\u01D8': 'u', + '\u01D6': 'u', + '\u01DA': 'u', + '\u1EE7': 'u', + '\u016F': 'u', + '\u0171': 'u', + '\u01D4': 'u', + '\u0215': 'u', + '\u0217': 'u', + '\u01B0': 'u', + '\u1EEB': 'u', + '\u1EE9': 'u', + '\u1EEF': 'u', + '\u1EED': 'u', + '\u1EF1': 'u', + '\u1EE5': 'u', + '\u1E73': 'u', + '\u0173': 'u', + '\u1E77': 'u', + '\u1E75': 'u', + '\u0289': 'u', + '\u24E5': 'v', + '\uFF56': 'v', + '\u1E7D': 'v', + '\u1E7F': 'v', + '\u028B': 'v', + '\uA75F': 'v', + '\u028C': 'v', + '\uA761': 'vy', + '\u24E6': 'w', + '\uFF57': 'w', + '\u1E81': 'w', + '\u1E83': 'w', + '\u0175': 'w', + '\u1E87': 'w', + '\u1E85': 'w', + '\u1E98': 'w', + '\u1E89': 'w', + '\u2C73': 'w', + '\u24E7': 'x', + '\uFF58': 'x', + '\u1E8B': 'x', + '\u1E8D': 'x', + '\u24E8': 'y', + '\uFF59': 'y', + '\u1EF3': 'y', + '\u00FD': 'y', + '\u0177': 'y', + '\u1EF9': 'y', + '\u0233': 'y', + '\u1E8F': 'y', + '\u00FF': 'y', + '\u1EF7': 'y', + '\u1E99': 'y', + '\u1EF5': 'y', + '\u01B4': 'y', + '\u024F': 'y', + '\u1EFF': 'y', + '\u24E9': 'z', + '\uFF5A': 'z', + '\u017A': 'z', + '\u1E91': 'z', + '\u017C': 'z', + '\u017E': 'z', + '\u1E93': 'z', + '\u1E95': 'z', + '\u01B6': 'z', + '\u0225': 'z', + '\u0240': 'z', + '\u2C6C': 'z', + '\uA763': 'z', + '\u0386': '\u0391', + '\u0388': '\u0395', + '\u0389': '\u0397', + '\u038A': '\u0399', + '\u03AA': '\u0399', + '\u038C': '\u039F', + '\u038E': '\u03A5', + '\u03AB': '\u03A5', + '\u038F': '\u03A9', + '\u03AC': '\u03B1', + '\u03AD': '\u03B5', + '\u03AE': '\u03B7', + '\u03AF': '\u03B9', + '\u03CA': '\u03B9', + '\u0390': '\u03B9', + '\u03CC': '\u03BF', + '\u03CD': '\u03C5', + '\u03CB': '\u03C5', + '\u03B0': '\u03C5', + '\u03C9': '\u03C9', + '\u03C2': '\u03C3' + }; + + return diacritics; +}); + +S2.define('select2/data/base',[ + '../utils' +], function (Utils) { + function BaseAdapter ($element, options) { + BaseAdapter.__super__.constructor.call(this); + } + + Utils.Extend(BaseAdapter, Utils.Observable); + + BaseAdapter.prototype.current = function (callback) { + throw new Error('The `current` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.query = function (params, callback) { + throw new Error('The `query` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.bind = function (container, $container) { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.destroy = function () { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.generateResultId = function (container, data) { + var id = container.id + '-result-'; + + id += Utils.generateChars(4); + + if (data.id != null) { + id += '-' + data.id.toString(); + } else { + id += '-' + Utils.generateChars(4); + } + return id; + }; + + return BaseAdapter; +}); + +S2.define('select2/data/select',[ + './base', + '../utils', + 'jquery' +], function (BaseAdapter, Utils, $) { + function SelectAdapter ($element, options) { + this.$element = $element; + this.options = options; + + SelectAdapter.__super__.constructor.call(this); + } + + Utils.Extend(SelectAdapter, BaseAdapter); + + SelectAdapter.prototype.current = function (callback) { + var data = []; + var self = this; + + this.$element.find(':selected').each(function () { + var $option = $(this); + + var option = self.item($option); + + data.push(option); + }); + + callback(data); + }; + + SelectAdapter.prototype.select = function (data) { + var self = this; + + data.selected = true; + + // If data.element is a DOM node, use it instead + if ($(data.element).is('option')) { + data.element.selected = true; + + this.$element.trigger('change'); + + return; + } + + if (this.$element.prop('multiple')) { + this.current(function (currentData) { + var val = []; + + data = [data]; + data.push.apply(data, currentData); + + for (var d = 0; d < data.length; d++) { + var id = data[d].id; + + if ($.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + self.$element.trigger('change'); + }); + } else { + var val = data.id; + + this.$element.val(val); + this.$element.trigger('change'); + } + }; + + SelectAdapter.prototype.unselect = function (data) { + var self = this; + + if (!this.$element.prop('multiple')) { + return; + } + + data.selected = false; + + if ($(data.element).is('option')) { + data.element.selected = false; + + this.$element.trigger('change'); + + return; + } + + this.current(function (currentData) { + var val = []; + + for (var d = 0; d < currentData.length; d++) { + var id = currentData[d].id; + + if (id !== data.id && $.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + + self.$element.trigger('change'); + }); + }; + + SelectAdapter.prototype.bind = function (container, $container) { + var self = this; + + this.container = container; + + container.on('select', function (params) { + self.select(params.data); + }); + + container.on('unselect', function (params) { + self.unselect(params.data); + }); + }; + + SelectAdapter.prototype.destroy = function () { + // Remove anything added to child elements + this.$element.find('*').each(function () { + // Remove any custom data set by Select2 + $.removeData(this, 'data'); + }); + }; + + SelectAdapter.prototype.query = function (params, callback) { + var data = []; + var self = this; + + var $options = this.$element.children(); + + $options.each(function () { + var $option = $(this); + + if (!$option.is('option') && !$option.is('optgroup')) { + return; + } + + var option = self.item($option); + + var matches = self.matches(params, option); + + if (matches !== null) { + data.push(matches); + } + }); + + callback({ + results: data + }); + }; + + SelectAdapter.prototype.addOptions = function ($options) { + Utils.appendMany(this.$element, $options); + }; + + SelectAdapter.prototype.option = function (data) { + var option; + + if (data.children) { + option = document.createElement('optgroup'); + option.label = data.text; + } else { + option = document.createElement('option'); + + if (option.textContent !== undefined) { + option.textContent = data.text; + } else { + option.innerText = data.text; + } + } + + if (data.id) { + option.value = data.id; + } + + if (data.disabled) { + option.disabled = true; + } + + if (data.selected) { + option.selected = true; + } + + if (data.title) { + option.title = data.title; + } + + var $option = $(option); + + var normalizedData = this._normalizeItem(data); + normalizedData.element = option; + + // Override the option's data with the combined data + $.data(option, 'data', normalizedData); + + return $option; + }; + + SelectAdapter.prototype.item = function ($option) { + var data = {}; + + data = $.data($option[0], 'data'); + + if (data != null) { + return data; + } + + if ($option.is('option')) { + data = { + id: $option.val(), + text: $option.text(), + disabled: $option.prop('disabled'), + selected: $option.prop('selected'), + title: $option.prop('title') + }; + } else if ($option.is('optgroup')) { + data = { + text: $option.prop('label'), + children: [], + title: $option.prop('title') + }; + + var $children = $option.children('option'); + var children = []; + + for (var c = 0; c < $children.length; c++) { + var $child = $($children[c]); + + var child = this.item($child); + + children.push(child); + } + + data.children = children; + } + + data = this._normalizeItem(data); + data.element = $option[0]; + + $.data($option[0], 'data', data); + + return data; + }; + + SelectAdapter.prototype._normalizeItem = function (item) { + if (!$.isPlainObject(item)) { + item = { + id: item, + text: item + }; + } + + item = $.extend({}, { + text: '' + }, item); + + var defaults = { + selected: false, + disabled: false + }; + + if (item.id != null) { + item.id = item.id.toString(); + } + + if (item.text != null) { + item.text = item.text.toString(); + } + + if (item._resultId == null && item.id && this.container != null) { + item._resultId = this.generateResultId(this.container, item); + } + + return $.extend({}, defaults, item); + }; + + SelectAdapter.prototype.matches = function (params, data) { + var matcher = this.options.get('matcher'); + + return matcher(params, data); + }; + + return SelectAdapter; +}); + +S2.define('select2/data/array',[ + './select', + '../utils', + 'jquery' +], function (SelectAdapter, Utils, $) { + function ArrayAdapter ($element, options) { + var data = options.get('data') || []; + + ArrayAdapter.__super__.constructor.call(this, $element, options); + + this.addOptions(this.convertToOptions(data)); + } + + Utils.Extend(ArrayAdapter, SelectAdapter); + + ArrayAdapter.prototype.select = function (data) { + var $option = this.$element.find('option').filter(function (i, elm) { + return elm.value == data.id.toString(); + }); + + if ($option.length === 0) { + $option = this.option(data); + + this.addOptions($option); + } + + ArrayAdapter.__super__.select.call(this, data); + }; + + ArrayAdapter.prototype.convertToOptions = function (data) { + var self = this; + + var $existing = this.$element.find('option'); + var existingIds = $existing.map(function () { + return self.item($(this)).id; + }).get(); + + var $options = []; + + // Filter out all items except for the one passed in the argument + function onlyItem (item) { + return function () { + return $(this).val() == item.id; + }; + } + + for (var d = 0; d < data.length; d++) { + var item = this._normalizeItem(data[d]); + + // Skip items which were pre-loaded, only merge the data + if ($.inArray(item.id, existingIds) >= 0) { + var $existingOption = $existing.filter(onlyItem(item)); + + var existingData = this.item($existingOption); + var newData = $.extend(true, {}, item, existingData); + + var $newOption = this.option(newData); + + $existingOption.replaceWith($newOption); + + continue; + } + + var $option = this.option(item); + + if (item.children) { + var $children = this.convertToOptions(item.children); + + Utils.appendMany($option, $children); + } + + $options.push($option); + } + + return $options; + }; + + return ArrayAdapter; +}); + +S2.define('select2/data/ajax',[ + './array', + '../utils', + 'jquery' +], function (ArrayAdapter, Utils, $) { + function AjaxAdapter ($element, options) { + this.ajaxOptions = this._applyDefaults(options.get('ajax')); + + if (this.ajaxOptions.processResults != null) { + this.processResults = this.ajaxOptions.processResults; + } + + AjaxAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(AjaxAdapter, ArrayAdapter); + + AjaxAdapter.prototype._applyDefaults = function (options) { + var defaults = { + data: function (params) { + return $.extend({}, params, { + q: params.term + }); + }, + transport: function (params, success, failure) { + var $request = $.ajax(params); + + $request.then(success); + $request.fail(failure); + + return $request; + } + }; + + return $.extend({}, defaults, options, true); + }; + + AjaxAdapter.prototype.processResults = function (results) { + return results; + }; + + AjaxAdapter.prototype.query = function (params, callback) { + var matches = []; + var self = this; + + if (this._request != null) { + // JSONP requests cannot always be aborted + if ($.isFunction(this._request.abort)) { + this._request.abort(); + } + + this._request = null; + } + + var options = $.extend({ + type: 'GET' + }, this.ajaxOptions); + + if (typeof options.url === 'function') { + options.url = options.url.call(this.$element, params); + } + + if (typeof options.data === 'function') { + options.data = options.data.call(this.$element, params); + } + + function request () { + var $request = options.transport(options, function (data) { + var results = self.processResults(data, params); + + if (self.options.get('debug') && window.console && console.error) { + // Check to make sure that the response included a `results` key. + if (!results || !results.results || !$.isArray(results.results)) { + console.error( + 'Select2: The AJAX results did not return an array in the ' + + '`results` key of the response.' + ); + } + } + + callback(results); + }, function () { + // Attempt to detect if a request was aborted + // Only works if the transport exposes a status property + if ($request.status && $request.status === '0') { + return; + } + + self.trigger('results:message', { + message: 'errorLoading' + }); + }); + + self._request = $request; + } + + if (this.ajaxOptions.delay && params.term != null) { + if (this._queryTimeout) { + window.clearTimeout(this._queryTimeout); + } + + this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay); + } else { + request(); + } + }; + + return AjaxAdapter; +}); + +S2.define('select2/data/tags',[ + 'jquery' +], function ($) { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + var createTag = options.get('createTag'); + + if (createTag !== undefined) { + this.createTag = createTag; + } + + var insertTag = options.get('insertTag'); + + if (insertTag !== undefined) { + this.insertTag = insertTag; + } + + decorated.call(this, $element, options); + + if ($.isArray(tags)) { + for (var t = 0; t < tags.length; t++) { + var tag = tags[t]; + var item = this._normalizeItem(tag); + + var $option = this.option(item); + + this.$element.append($option); + } + } + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + this._removeOldTags(); + + if (params.term == null || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (obj, child) { + var data = obj.results; + + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && + !wrapper({ + results: option.children + }, true) + ); + + var checkText = option.text === params.term; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + obj.data = data; + callback(obj); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + + if (tag != null) { + var $option = self.option(tag); + $option.attr('data-select2-tag', true); + + self.addOptions([$option]); + + self.insertTag(data, tag); + } + + obj.results = data; + + callback(obj); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + var term = $.trim(params.term); + + if (term === '') { + return null; + } + + return { + id: term, + text: term + }; + }; + + Tags.prototype.insertTag = function (_, data, tag) { + data.unshift(tag); + }; + + Tags.prototype._removeOldTags = function (_) { + var tag = this._lastTag; + + var $options = this.$element.find('option[data-select2-tag]'); + + $options.each(function () { + if (this.selected) { + return; + } + + $(this).remove(); + }); + }; + + return Tags; +}); + +S2.define('select2/data/tokenizer',[ + 'jquery' +], function ($) { + function Tokenizer (decorated, $element, options) { + var tokenizer = options.get('tokenizer'); + + if (tokenizer !== undefined) { + this.tokenizer = tokenizer; + } + + decorated.call(this, $element, options); + } + + Tokenizer.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); + + this.$search = container.dropdown.$search || container.selection.$search || + $container.find('.select2-search__field'); + }; + + Tokenizer.prototype.query = function (decorated, params, callback) { + var self = this; + + function createAndSelect (data) { + // Normalize the data object so we can use it for checks + var item = self._normalizeItem(data); + + // Check if the data object already exists as a tag + // Select it if it doesn't + var $existingOptions = self.$element.find('option').filter(function () { + return $(this).val() === item.id; + }); + + // If an existing option wasn't found for it, create the option + if (!$existingOptions.length) { + var $option = self.option(item); + $option.attr('data-select2-tag', true); + + self._removeOldTags(); + self.addOptions([$option]); + } + + // Select the item, now that we know there is an option for it + select(item); + } + + function select (data) { + self.trigger('select', { + data: data + }); + } + + params.term = params.term || ''; + + var tokenData = this.tokenizer(params, this.options, createAndSelect); + + if (tokenData.term !== params.term) { + // Replace the search term if we have the search box + if (this.$search.length) { + this.$search.val(tokenData.term); + this.$search.focus(); + } + + params.term = tokenData.term; + } + + decorated.call(this, params, callback); + }; + + Tokenizer.prototype.tokenizer = function (_, params, options, callback) { + var separators = options.get('tokenSeparators') || []; + var term = params.term; + var i = 0; + + var createTag = this.createTag || function (params) { + return { + id: params.term, + text: params.term + }; + }; + + while (i < term.length) { + var termChar = term[i]; + + if ($.inArray(termChar, separators) === -1) { + i++; + + continue; + } + + var part = term.substr(0, i); + var partParams = $.extend({}, params, { + term: part + }); + + var data = createTag(partParams); + + if (data == null) { + i++; + continue; + } + + callback(data); + + // Reset the term to not include the tokenized portion + term = term.substr(i + 1) || ''; + i = 0; + } + + return { + term: term + }; + }; + + return Tokenizer; +}); + +S2.define('select2/data/minimumInputLength',[ + +], function () { + function MinimumInputLength (decorated, $e, options) { + this.minimumInputLength = options.get('minimumInputLength'); + + decorated.call(this, $e, options); + } + + MinimumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (params.term.length < this.minimumInputLength) { + this.trigger('results:message', { + message: 'inputTooShort', + args: { + minimum: this.minimumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MinimumInputLength; +}); + +S2.define('select2/data/maximumInputLength',[ + +], function () { + function MaximumInputLength (decorated, $e, options) { + this.maximumInputLength = options.get('maximumInputLength'); + + decorated.call(this, $e, options); + } + + MaximumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (this.maximumInputLength > 0 && + params.term.length > this.maximumInputLength) { + this.trigger('results:message', { + message: 'inputTooLong', + args: { + maximum: this.maximumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MaximumInputLength; +}); + +S2.define('select2/data/maximumSelectionLength',[ + +], function (){ + function MaximumSelectionLength (decorated, $e, options) { + this.maximumSelectionLength = options.get('maximumSelectionLength'); + + decorated.call(this, $e, options); + } + + MaximumSelectionLength.prototype.query = + function (decorated, params, callback) { + var self = this; + + this.current(function (currentData) { + var count = currentData != null ? currentData.length : 0; + if (self.maximumSelectionLength > 0 && + count >= self.maximumSelectionLength) { + self.trigger('results:message', { + message: 'maximumSelected', + args: { + maximum: self.maximumSelectionLength + } + }); + return; + } + decorated.call(self, params, callback); + }); + }; + + return MaximumSelectionLength; +}); + +S2.define('select2/dropdown',[ + 'jquery', + './utils' +], function ($, Utils) { + function Dropdown ($element, options) { + this.$element = $element; + this.options = options; + + Dropdown.__super__.constructor.call(this); + } + + Utils.Extend(Dropdown, Utils.Observable); + + Dropdown.prototype.render = function () { + var $dropdown = $( + '' + + '' + + '' + ); + + $dropdown.attr('dir', this.options.get('dir')); + + this.$dropdown = $dropdown; + + return $dropdown; + }; + + Dropdown.prototype.bind = function () { + // Should be implemented in subclasses + }; + + Dropdown.prototype.position = function ($dropdown, $container) { + // Should be implmented in subclasses + }; + + Dropdown.prototype.destroy = function () { + // Remove the dropdown from the DOM + this.$dropdown.remove(); + }; + + return Dropdown; +}); + +S2.define('select2/dropdown/search',[ + 'jquery', + '../utils' +], function ($, Utils) { + function Search () { } + + Search.prototype.render = function (decorated) { + var $rendered = decorated.call(this); + + var $search = $( + '' + + '' + + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + $rendered.prepend($search); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + this.$search.on('keydown', function (evt) { + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + }); + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$search.on('input', function (evt) { + // Unbind the duplicated `keyup` event + $(this).off('keyup'); + }); + + this.$search.on('keyup input', function (evt) { + self.handleSearch(evt); + }); + + container.on('open', function () { + self.$search.attr('tabindex', 0); + + self.$search.focus(); + + window.setTimeout(function () { + self.$search.focus(); + }, 0); + }); + + container.on('close', function () { + self.$search.attr('tabindex', -1); + + self.$search.val(''); + }); + + container.on('focus', function () { + if (container.isOpen()) { + self.$search.focus(); + } + }); + + container.on('results:all', function (params) { + if (params.query.term == null || params.query.term === '') { + var showSearch = self.showSearch(params); + + if (showSearch) { + self.$searchContainer.removeClass('select2-search--hide'); + } else { + self.$searchContainer.addClass('select2-search--hide'); + } + } + }); + }; + + Search.prototype.handleSearch = function (evt) { + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.showSearch = function (_, params) { + return true; + }; + + return Search; +}); + +S2.define('select2/dropdown/hidePlaceholder',[ + +], function () { + function HidePlaceholder (decorated, $element, options, dataAdapter) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options, dataAdapter); + } + + HidePlaceholder.prototype.append = function (decorated, data) { + data.results = this.removePlaceholder(data.results); + + decorated.call(this, data); + }; + + HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + HidePlaceholder.prototype.removePlaceholder = function (_, data) { + var modifiedData = data.slice(0); + + for (var d = data.length - 1; d >= 0; d--) { + var item = data[d]; + + if (this.placeholder.id === item.id) { + modifiedData.splice(d, 1); + } + } + + return modifiedData; + }; + + return HidePlaceholder; +}); + +S2.define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + this.loading = false; + + decorated.call(this, data); + + if (this.showLoadingMore(data)) { + this.$results.append(this.$loadingMore); + } + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + self.$loadingMore[0] + ); + + if (self.loading || !isLoadMoreVisible) { + return; + } + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var loadingMoreOffset = self.$loadingMore.offset().top + + self.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + self.loadMore(); + } + }); + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.showLoadingMore = function (_, data) { + return data.pagination && data.pagination.more; + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
      • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + +S2.define('select2/dropdown/attachBody',[ + 'jquery', + '../utils' +], function ($, Utils) { + function AttachBody (decorated, $element, options) { + this.$dropdownParent = options.get('dropdownParent') || $(document.body); + + decorated.call(this, $element, options); + } + + AttachBody.prototype.bind = function (decorated, container, $container) { + var self = this; + + var setupResultsEvents = false; + + decorated.call(this, container, $container); + + container.on('open', function () { + self._showDropdown(); + self._attachPositioningHandler(container); + + if (!setupResultsEvents) { + setupResultsEvents = true; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + } + }); + + container.on('close', function () { + self._hideDropdown(); + self._detachPositioningHandler(container); + }); + + this.$dropdownContainer.on('mousedown', function (evt) { + evt.stopPropagation(); + }); + }; + + AttachBody.prototype.destroy = function (decorated) { + decorated.call(this); + + this.$dropdownContainer.remove(); + }; + + AttachBody.prototype.position = function (decorated, $dropdown, $container) { + // Clone all of the container classes + $dropdown.attr('class', $container.attr('class')); + + $dropdown.removeClass('select2'); + $dropdown.addClass('select2-container--open'); + + $dropdown.css({ + position: 'absolute', + top: -999999 + }); + + this.$container = $container; + }; + + AttachBody.prototype.render = function (decorated) { + var $container = $(''); + + var $dropdown = decorated.call(this); + $container.append($dropdown); + + this.$dropdownContainer = $container; + + return $container; + }; + + AttachBody.prototype._hideDropdown = function (decorated) { + this.$dropdownContainer.detach(); + }; + + AttachBody.prototype._attachPositioningHandler = + function (decorated, container) { + var self = this; + + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.each(function () { + $(this).data('select2-scroll-position', { + x: $(this).scrollLeft(), + y: $(this).scrollTop() + }); + }); + + $watchers.on(scrollEvent, function (ev) { + var position = $(this).data('select2-scroll-position'); + $(this).scrollTop(position.y); + }); + + $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, + function (e) { + self._positionDropdown(); + self._resizeDropdown(); + }); + }; + + AttachBody.prototype._detachPositioningHandler = + function (decorated, container) { + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.off(scrollEvent); + + $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent); + }; + + AttachBody.prototype._positionDropdown = function () { + var $window = $(window); + + var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above'); + var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below'); + + var newDirection = null; + + var offset = this.$container.offset(); + + offset.bottom = offset.top + this.$container.outerHeight(false); + + var container = { + height: this.$container.outerHeight(false) + }; + + container.top = offset.top; + container.bottom = offset.top + container.height; + + var dropdown = { + height: this.$dropdown.outerHeight(false) + }; + + var viewport = { + top: $window.scrollTop(), + bottom: $window.scrollTop() + $window.height() + }; + + var enoughRoomAbove = viewport.top < (offset.top - dropdown.height); + var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height); + + var css = { + left: offset.left, + top: container.bottom + }; + + // Determine what the parent element is to use for calciulating the offset + var $offsetParent = this.$dropdownParent; + + // For statically positoned elements, we need to get the element + // that is determining the offset + if ($offsetParent.css('position') === 'static') { + $offsetParent = $offsetParent.offsetParent(); + } + + var parentOffset = $offsetParent.offset(); + + css.top -= parentOffset.top; + css.left -= parentOffset.left; + + if (!isCurrentlyAbove && !isCurrentlyBelow) { + newDirection = 'below'; + } + + if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) { + newDirection = 'above'; + } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) { + newDirection = 'below'; + } + + if (newDirection == 'above' || + (isCurrentlyAbove && newDirection !== 'below')) { + css.top = container.top - parentOffset.top - dropdown.height; + } + + if (newDirection != null) { + this.$dropdown + .removeClass('select2-dropdown--below select2-dropdown--above') + .addClass('select2-dropdown--' + newDirection); + this.$container + .removeClass('select2-container--below select2-container--above') + .addClass('select2-container--' + newDirection); + } + + this.$dropdownContainer.css(css); + }; + + AttachBody.prototype._resizeDropdown = function () { + var css = { + width: this.$container.outerWidth(false) + 'px' + }; + + if (this.options.get('dropdownAutoWidth')) { + css.minWidth = css.width; + css.position = 'relative'; + css.width = 'auto'; + } + + this.$dropdown.css(css); + }; + + AttachBody.prototype._showDropdown = function (decorated) { + this.$dropdownContainer.appendTo(this.$dropdownParent); + + this._positionDropdown(); + this._resizeDropdown(); + }; + + return AttachBody; +}); + +S2.define('select2/dropdown/minimumResultsForSearch',[ + +], function () { + function countResults (data) { + var count = 0; + + for (var d = 0; d < data.length; d++) { + var item = data[d]; + + if (item.children) { + count += countResults(item.children); + } else { + count++; + } + } + + return count; + } + + function MinimumResultsForSearch (decorated, $element, options, dataAdapter) { + this.minimumResultsForSearch = options.get('minimumResultsForSearch'); + + if (this.minimumResultsForSearch < 0) { + this.minimumResultsForSearch = Infinity; + } + + decorated.call(this, $element, options, dataAdapter); + } + + MinimumResultsForSearch.prototype.showSearch = function (decorated, params) { + if (countResults(params.data.results) < this.minimumResultsForSearch) { + return false; + } + + return decorated.call(this, params); + }; + + return MinimumResultsForSearch; +}); + +S2.define('select2/dropdown/selectOnClose',[ + +], function () { + function SelectOnClose () { } + + SelectOnClose.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('close', function (params) { + self._handleSelectOnClose(params); + }); + }; + + SelectOnClose.prototype._handleSelectOnClose = function (_, params) { + if (params && params.originalSelect2Event != null) { + var event = params.originalSelect2Event; + + // Don't select an item if the close event was triggered from a select or + // unselect event + if (event._type === 'select' || event._type === 'unselect') { + return; + } + } + + var $highlightedResults = this.getHighlightedResults(); + + // Only select highlighted results + if ($highlightedResults.length < 1) { + return; + } + + var data = $highlightedResults.data('data'); + + // Don't re-select already selected resulte + if ( + (data.element != null && data.element.selected) || + (data.element == null && data.selected) + ) { + return; + } + + this.trigger('select', { + data: data + }); + }; + + return SelectOnClose; +}); + +S2.define('select2/dropdown/closeOnSelect',[ + +], function () { + function CloseOnSelect () { } + + CloseOnSelect.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function (evt) { + self._selectTriggered(evt); + }); + + container.on('unselect', function (evt) { + self._selectTriggered(evt); + }); + }; + + CloseOnSelect.prototype._selectTriggered = function (_, evt) { + var originalEvent = evt.originalEvent; + + // Don't close if the control key is being held + if (originalEvent && originalEvent.ctrlKey) { + return; + } + + this.trigger('close', { + originalEvent: originalEvent, + originalSelect2Event: evt + }); + }; + + return CloseOnSelect; +}); + +S2.define('select2/i18n/en',[],function () { + // English + return { + errorLoading: function () { + return 'The results could not be loaded.'; + }, + inputTooLong: function (args) { + var overChars = args.input.length - args.maximum; + + var message = 'Please delete ' + overChars + ' character'; + + if (overChars != 1) { + message += 's'; + } + + return message; + }, + inputTooShort: function (args) { + var remainingChars = args.minimum - args.input.length; + + var message = 'Please enter ' + remainingChars + ' or more characters'; + + return message; + }, + loadingMore: function () { + return 'Loading more results…'; + }, + maximumSelected: function (args) { + var message = 'You can only select ' + args.maximum + ' item'; + + if (args.maximum != 1) { + message += 's'; + } + + return message; + }, + noResults: function () { + return 'No results found'; + }, + searching: function () { + return 'Searching…'; + } + }; +}); + +S2.define('select2/defaults',[ + 'jquery', + 'require', + + './results', + + './selection/single', + './selection/multiple', + './selection/placeholder', + './selection/allowClear', + './selection/search', + './selection/eventRelay', + + './utils', + './translation', + './diacritics', + + './data/select', + './data/array', + './data/ajax', + './data/tags', + './data/tokenizer', + './data/minimumInputLength', + './data/maximumInputLength', + './data/maximumSelectionLength', + + './dropdown', + './dropdown/search', + './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', + './dropdown/attachBody', + './dropdown/minimumResultsForSearch', + './dropdown/selectOnClose', + './dropdown/closeOnSelect', + + './i18n/en' +], function ($, require, + + ResultsList, + + SingleSelection, MultipleSelection, Placeholder, AllowClear, + SelectionSearch, EventRelay, + + Utils, Translation, DIACRITICS, + + SelectData, ArrayData, AjaxData, Tags, Tokenizer, + MinimumInputLength, MaximumInputLength, MaximumSelectionLength, + + Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, + AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, + + EnglishTranslation) { + function Defaults () { + this.reset(); + } + + Defaults.prototype.apply = function (options) { + options = $.extend(true, {}, this.defaults, options); + + if (options.dataAdapter == null) { + if (options.ajax != null) { + options.dataAdapter = AjaxData; + } else if (options.data != null) { + options.dataAdapter = ArrayData; + } else { + options.dataAdapter = SelectData; + } + + if (options.minimumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MinimumInputLength + ); + } + + if (options.maximumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumInputLength + ); + } + + if (options.maximumSelectionLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumSelectionLength + ); + } + + if (options.tags) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + + if (options.tokenSeparators != null || options.tokenizer != null) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Tokenizer + ); + } + + if (options.query != null) { + var Query = require(options.amdBase + 'compat/query'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Query + ); + } + + if (options.initSelection != null) { + var InitSelection = require(options.amdBase + 'compat/initSelection'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + InitSelection + ); + } + } + + if (options.resultsAdapter == null) { + options.resultsAdapter = ResultsList; + + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + + if (options.placeholder != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + HidePlaceholder + ); + } + + if (options.selectOnClose) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + SelectOnClose + ); + } + } + + if (options.dropdownAdapter == null) { + if (options.multiple) { + options.dropdownAdapter = Dropdown; + } else { + var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch); + + options.dropdownAdapter = SearchableDropdown; + } + + if (options.minimumResultsForSearch !== 0) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + MinimumResultsForSearch + ); + } + + if (options.closeOnSelect) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + CloseOnSelect + ); + } + + if ( + options.dropdownCssClass != null || + options.dropdownCss != null || + options.adaptDropdownCssClass != null + ) { + var DropdownCSS = require(options.amdBase + 'compat/dropdownCss'); + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + DropdownCSS + ); + } + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + AttachBody + ); + } + + if (options.selectionAdapter == null) { + if (options.multiple) { + options.selectionAdapter = MultipleSelection; + } else { + options.selectionAdapter = SingleSelection; + } + + // Add the placeholder mixin if a placeholder was specified + if (options.placeholder != null) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + Placeholder + ); + } + + if (options.allowClear) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + AllowClear + ); + } + + if (options.multiple) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + SelectionSearch + ); + } + + if ( + options.containerCssClass != null || + options.containerCss != null || + options.adaptContainerCssClass != null + ) { + var ContainerCSS = require(options.amdBase + 'compat/containerCss'); + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + ContainerCSS + ); + } + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + EventRelay + ); + } + + if (typeof options.language === 'string') { + // Check if the language is specified with a region + if (options.language.indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = options.language.split('-'); + var baseLanguage = languageParts[0]; + + options.language = [options.language, baseLanguage]; + } else { + options.language = [options.language]; + } + } + + if ($.isArray(options.language)) { + var languages = new Translation(); + options.language.push('en'); + + var languageNames = options.language; + + for (var l = 0; l < languageNames.length; l++) { + var name = languageNames[l]; + var language = {}; + + try { + // Try to load it with the original name + language = Translation.loadPath(name); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + name = this.defaults.amdLanguageBase + name; + language = Translation.loadPath(name); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files. + if (options.debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + name + '" could not be ' + + 'automatically loaded. A fallback will be used instead.' + ); + } + + continue; + } + } + + languages.extend(language); + } + + options.translations = languages; + } else { + var baseTranslation = Translation.loadPath( + this.defaults.amdLanguageBase + 'en' + ); + var customTranslation = new Translation(options.language); + + customTranslation.extend(baseTranslation); + + options.translations = customTranslation; + } + + return options; + }; + + Defaults.prototype.reset = function () { + function stripDiacritics (text) { + // Used 'uni range + named function' from http://jsperf.com/diacritics/18 + function match(a) { + return DIACRITICS[a] || a; + } + + return text.replace(/[^\u0000-\u007E]/g, match); + } + + function matcher (params, data) { + // Always return the object if there is nothing to compare + if ($.trim(params.term) === '') { + return data; + } + + // Do a recursive check for options with children + if (data.children && data.children.length > 0) { + // Clone the data object if there are children + // This is required as we modify the object to remove any non-matches + var match = $.extend(true, {}, data); + + // Check each child of the option + for (var c = data.children.length - 1; c >= 0; c--) { + var child = data.children[c]; + + var matches = matcher(params, child); + + // If there wasn't a match, remove the object in the array + if (matches == null) { + match.children.splice(c, 1); + } + } + + // If any children matched, return the new object + if (match.children.length > 0) { + return match; + } + + // If there were no matching children, check just the plain object + return matcher(params, match); + } + + var original = stripDiacritics(data.text).toUpperCase(); + var term = stripDiacritics(params.term).toUpperCase(); + + // Check if the text contains the term + if (original.indexOf(term) > -1) { + return data; + } + + // If it doesn't contain the term, don't return anything + return null; + } + + this.defaults = { + amdBase: './', + amdLanguageBase: './i18n/', + closeOnSelect: true, + debug: false, + dropdownAutoWidth: false, + escapeMarkup: Utils.escapeMarkup, + language: EnglishTranslation, + matcher: matcher, + minimumInputLength: 0, + maximumInputLength: 0, + maximumSelectionLength: 0, + minimumResultsForSearch: 0, + selectOnClose: false, + sorter: function (data) { + return data; + }, + templateResult: function (result) { + return result.text; + }, + templateSelection: function (selection) { + return selection.text; + }, + theme: 'default', + width: 'resolve' + }; + }; + + Defaults.prototype.set = function (key, value) { + var camelKey = $.camelCase(key); + + var data = {}; + data[camelKey] = value; + + var convertedData = Utils._convertData(data); + + $.extend(this.defaults, convertedData); + }; + + var defaults = new Defaults(); + + return defaults; +}); + +S2.define('select2/options',[ + 'require', + 'jquery', + './defaults', + './utils' +], function (require, $, Defaults, Utils) { + function Options (options, $element) { + this.options = options; + + if ($element != null) { + this.fromElement($element); + } + + this.options = Defaults.apply(this.options); + + if ($element && $element.is('input')) { + var InputCompat = require(this.get('amdBase') + 'compat/inputData'); + + this.options.dataAdapter = Utils.Decorate( + this.options.dataAdapter, + InputCompat + ); + } + } + + Options.prototype.fromElement = function ($e) { + var excludedData = ['select2']; + + if (this.options.multiple == null) { + this.options.multiple = $e.prop('multiple'); + } + + if (this.options.disabled == null) { + this.options.disabled = $e.prop('disabled'); + } + + if (this.options.language == null) { + if ($e.prop('lang')) { + this.options.language = $e.prop('lang').toLowerCase(); + } else if ($e.closest('[lang]').prop('lang')) { + this.options.language = $e.closest('[lang]').prop('lang'); + } + } + + if (this.options.dir == null) { + if ($e.prop('dir')) { + this.options.dir = $e.prop('dir'); + } else if ($e.closest('[dir]').prop('dir')) { + this.options.dir = $e.closest('[dir]').prop('dir'); + } else { + this.options.dir = 'ltr'; + } + } + + $e.prop('disabled', this.options.disabled); + $e.prop('multiple', this.options.multiple); + + if ($e.data('select2Tags')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-select2-tags` attribute has been changed to ' + + 'use the `data-data` and `data-tags="true"` attributes and will be ' + + 'removed in future versions of Select2.' + ); + } + + $e.data('data', $e.data('select2Tags')); + $e.data('tags', true); + } + + if ($e.data('ajaxUrl')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-ajax-url` attribute has been changed to ' + + '`data-ajax--url` and support for the old attribute will be removed' + + ' in future versions of Select2.' + ); + } + + $e.attr('ajax--url', $e.data('ajaxUrl')); + $e.data('ajax--url', $e.data('ajaxUrl')); + } + + var dataset = {}; + + // Prefer the element's `dataset` attribute if it exists + // jQuery 1.x does not correctly handle data attributes with multiple dashes + if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { + dataset = $.extend(true, {}, $e[0].dataset, $e.data()); + } else { + dataset = $e.data(); + } + + var data = $.extend(true, {}, dataset); + + data = Utils._convertData(data); + + for (var key in data) { + if ($.inArray(key, excludedData) > -1) { + continue; + } + + if ($.isPlainObject(this.options[key])) { + $.extend(this.options[key], data[key]); + } else { + this.options[key] = data[key]; + } + } + + return this; + }; + + Options.prototype.get = function (key) { + return this.options[key]; + }; + + Options.prototype.set = function (key, val) { + this.options[key] = val; + }; + + return Options; +}); + +S2.define('select2/core',[ + 'jquery', + './options', + './utils', + './keys' +], function ($, Options, Utils, KEYS) { + var Select2 = function ($element, options) { + if ($element.data('select2') != null) { + $element.data('select2').destroy(); + } + + this.$element = $element; + + this.id = this._generateId($element); + + options = options || {}; + + this.options = new Options(options, $element); + + Select2.__super__.constructor.call(this); + + // Set up the tabindex + + var tabindex = $element.attr('tabindex') || 0; + $element.data('old-tabindex', tabindex); + $element.attr('tabindex', '-1'); + + // Set up containers and adapters + + var DataAdapter = this.options.get('dataAdapter'); + this.dataAdapter = new DataAdapter($element, this.options); + + var $container = this.render(); + + this._placeContainer($container); + + var SelectionAdapter = this.options.get('selectionAdapter'); + this.selection = new SelectionAdapter($element, this.options); + this.$selection = this.selection.render(); + + this.selection.position(this.$selection, $container); + + var DropdownAdapter = this.options.get('dropdownAdapter'); + this.dropdown = new DropdownAdapter($element, this.options); + this.$dropdown = this.dropdown.render(); + + this.dropdown.position(this.$dropdown, $container); + + var ResultsAdapter = this.options.get('resultsAdapter'); + this.results = new ResultsAdapter($element, this.options, this.dataAdapter); + this.$results = this.results.render(); + + this.results.position(this.$results, this.$dropdown); + + // Bind events + + var self = this; + + // Bind the container to all of the adapters + this._bindAdapters(); + + // Register any DOM event handlers + this._registerDomEvents(); + + // Register any internal event handlers + this._registerDataEvents(); + this._registerSelectionEvents(); + this._registerDropdownEvents(); + this._registerResultsEvents(); + this._registerEvents(); + + // Set the initial state + this.dataAdapter.current(function (initialData) { + self.trigger('selection:update', { + data: initialData + }); + }); + + // Hide the original select + $element.addClass('select2-hidden-accessible'); + $element.attr('aria-hidden', 'true'); + + // Synchronize any monitored attributes + this._syncAttributes(); + + $element.data('select2', this); + }; + + Utils.Extend(Select2, Utils.Observable); + + Select2.prototype._generateId = function ($element) { + var id = ''; + + if ($element.attr('id') != null) { + id = $element.attr('id'); + } else if ($element.attr('name') != null) { + id = $element.attr('name') + '-' + Utils.generateChars(2); + } else { + id = Utils.generateChars(4); + } + + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = 'select2-' + id; + + return id; + }; + + Select2.prototype._placeContainer = function ($container) { + $container.insertAfter(this.$element); + + var width = this._resolveWidth(this.$element, this.options.get('width')); + + if (width != null) { + $container.css('width', width); + } + }; + + Select2.prototype._resolveWidth = function ($element, method) { + var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i; + + if (method == 'resolve') { + var styleWidth = this._resolveWidth($element, 'style'); + + if (styleWidth != null) { + return styleWidth; + } + + return this._resolveWidth($element, 'element'); + } + + if (method == 'element') { + var elementWidth = $element.outerWidth(false); + + if (elementWidth <= 0) { + return 'auto'; + } + + return elementWidth + 'px'; + } + + if (method == 'style') { + var style = $element.attr('style'); + + if (typeof(style) !== 'string') { + return null; + } + + var attrs = style.split(';'); + + for (var i = 0, l = attrs.length; i < l; i = i + 1) { + var attr = attrs[i].replace(/\s/g, ''); + var matches = attr.match(WIDTH); + + if (matches !== null && matches.length >= 1) { + return matches[1]; + } + } + + return null; + } + + return method; + }; + + Select2.prototype._bindAdapters = function () { + this.dataAdapter.bind(this, this.$container); + this.selection.bind(this, this.$container); + + this.dropdown.bind(this, this.$container); + this.results.bind(this, this.$container); + }; + + Select2.prototype._registerDomEvents = function () { + var self = this; + + this.$element.on('change.select2', function () { + self.dataAdapter.current(function (data) { + self.trigger('selection:update', { + data: data + }); + }); + }); + + this.$element.on('focus.select2', function (evt) { + self.trigger('focus', evt); + }); + + this._syncA = Utils.bind(this._syncAttributes, this); + this._syncS = Utils.bind(this._syncSubtree, this); + + if (this.$element[0].attachEvent) { + this.$element[0].attachEvent('onpropertychange', this._syncA); + } + + var observer = window.MutationObserver || + window.WebKitMutationObserver || + window.MozMutationObserver + ; + + if (observer != null) { + this._observer = new observer(function (mutations) { + $.each(mutations, self._syncA); + $.each(mutations, self._syncS); + }); + this._observer.observe(this.$element[0], { + attributes: true, + childList: true, + subtree: false + }); + } else if (this.$element[0].addEventListener) { + this.$element[0].addEventListener( + 'DOMAttrModified', + self._syncA, + false + ); + this.$element[0].addEventListener( + 'DOMNodeInserted', + self._syncS, + false + ); + this.$element[0].addEventListener( + 'DOMNodeRemoved', + self._syncS, + false + ); + } + }; + + Select2.prototype._registerDataEvents = function () { + var self = this; + + this.dataAdapter.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerSelectionEvents = function () { + var self = this; + var nonRelayEvents = ['toggle', 'focus']; + + this.selection.on('toggle', function () { + self.toggleDropdown(); + }); + + this.selection.on('focus', function (params) { + self.focus(params); + }); + + this.selection.on('*', function (name, params) { + if ($.inArray(name, nonRelayEvents) !== -1) { + return; + } + + self.trigger(name, params); + }); + }; + + Select2.prototype._registerDropdownEvents = function () { + var self = this; + + this.dropdown.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerResultsEvents = function () { + var self = this; + + this.results.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerEvents = function () { + var self = this; + + this.on('open', function () { + self.$container.addClass('select2-container--open'); + }); + + this.on('close', function () { + self.$container.removeClass('select2-container--open'); + }); + + this.on('enable', function () { + self.$container.removeClass('select2-container--disabled'); + }); + + this.on('disable', function () { + self.$container.addClass('select2-container--disabled'); + }); + + this.on('blur', function () { + self.$container.removeClass('select2-container--focus'); + }); + + this.on('query', function (params) { + if (!self.isOpen()) { + self.trigger('open', {}); + } + + this.dataAdapter.query(params, function (data) { + self.trigger('results:all', { + data: data, + query: params + }); + }); + }); + + this.on('query:append', function (params) { + this.dataAdapter.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + + this.on('keypress', function (evt) { + var key = evt.which; + + if (self.isOpen()) { + if (key === KEYS.ESC || key === KEYS.TAB || + (key === KEYS.UP && evt.altKey)) { + self.close(); + + evt.preventDefault(); + } else if (key === KEYS.ENTER) { + self.trigger('results:select', {}); + + evt.preventDefault(); + } else if ((key === KEYS.SPACE && evt.ctrlKey)) { + self.trigger('results:toggle', {}); + + evt.preventDefault(); + } else if (key === KEYS.UP) { + self.trigger('results:previous', {}); + + evt.preventDefault(); + } else if (key === KEYS.DOWN) { + self.trigger('results:next', {}); + + evt.preventDefault(); + } + } else { + if (key === KEYS.ENTER || key === KEYS.SPACE || + (key === KEYS.DOWN && evt.altKey)) { + self.open(); + + evt.preventDefault(); + } + } + }); + }; + + Select2.prototype._syncAttributes = function () { + this.options.set('disabled', this.$element.prop('disabled')); + + if (this.options.get('disabled')) { + if (this.isOpen()) { + this.close(); + } + + this.trigger('disable', {}); + } else { + this.trigger('enable', {}); + } + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = false; + var self = this; + + // Ignore any mutation events raised for elements that aren't options or + // optgroups. This handles the case when the select element is destroyed + if ( + evt && evt.target && ( + evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP' + ) + ) { + return; + } + + if (!mutations) { + // If mutation events aren't supported, then we can only assume that the + // change affected the selections + changed = true; + } else if (mutations.addedNodes && mutations.addedNodes.length > 0) { + for (var n = 0; n < mutations.addedNodes.length; n++) { + var node = mutations.addedNodes[n]; + + if (node.selected) { + changed = true; + } + } + } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { + changed = true; + } + + // Only re-pull the data if we think there is a change + if (changed) { + this.dataAdapter.current(function (currentData) { + self.trigger('selection:update', { + data: currentData + }); + }); + } + }; + + /** + * Override the trigger method to automatically trigger pre-events when + * there are events that can be prevented. + */ + Select2.prototype.trigger = function (name, args) { + var actualTrigger = Select2.__super__.trigger; + var preTriggerMap = { + 'open': 'opening', + 'close': 'closing', + 'select': 'selecting', + 'unselect': 'unselecting' + }; + + if (args === undefined) { + args = {}; + } + + if (name in preTriggerMap) { + var preTriggerName = preTriggerMap[name]; + var preTriggerArgs = { + prevented: false, + name: name, + args: args + }; + + actualTrigger.call(this, preTriggerName, preTriggerArgs); + + if (preTriggerArgs.prevented) { + args.prevented = true; + + return; + } + } + + actualTrigger.call(this, name, args); + }; + + Select2.prototype.toggleDropdown = function () { + if (this.options.get('disabled')) { + return; + } + + if (this.isOpen()) { + this.close(); + } else { + this.open(); + } + }; + + Select2.prototype.open = function () { + if (this.isOpen()) { + return; + } + + this.trigger('query', {}); + }; + + Select2.prototype.close = function () { + if (!this.isOpen()) { + return; + } + + this.trigger('close', {}); + }; + + Select2.prototype.isOpen = function () { + return this.$container.hasClass('select2-container--open'); + }; + + Select2.prototype.hasFocus = function () { + return this.$container.hasClass('select2-container--focus'); + }; + + Select2.prototype.focus = function (data) { + // No need to re-trigger focus events if we are already focused + if (this.hasFocus()) { + return; + } + + this.$container.addClass('select2-container--focus'); + this.trigger('focus', {}); + }; + + Select2.prototype.enable = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("enable")` method has been deprecated and will' + + ' be removed in later Select2 versions. Use $element.prop("disabled")' + + ' instead.' + ); + } + + if (args == null || args.length === 0) { + args = [true]; + } + + var disabled = !args[0]; + + this.$element.prop('disabled', disabled); + }; + + Select2.prototype.data = function () { + if (this.options.get('debug') && + arguments.length > 0 && window.console && console.warn) { + console.warn( + 'Select2: Data can no longer be set using `select2("data")`. You ' + + 'should consider setting the value instead using `$element.val()`.' + ); + } + + var data = []; + + this.dataAdapter.current(function (currentData) { + data = currentData; + }); + + return data; + }; + + Select2.prototype.val = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("val")` method has been deprecated and will be' + + ' removed in later Select2 versions. Use $element.val() instead.' + ); + } + + if (args == null || args.length === 0) { + return this.$element.val(); + } + + var newVal = args[0]; + + if ($.isArray(newVal)) { + newVal = $.map(newVal, function (obj) { + return obj.toString(); + }); + } + + this.$element.val(newVal).trigger('change'); + }; + + Select2.prototype.destroy = function () { + this.$container.remove(); + + if (this.$element[0].detachEvent) { + this.$element[0].detachEvent('onpropertychange', this._syncA); + } + + if (this._observer != null) { + this._observer.disconnect(); + this._observer = null; + } else if (this.$element[0].removeEventListener) { + this.$element[0] + .removeEventListener('DOMAttrModified', this._syncA, false); + this.$element[0] + .removeEventListener('DOMNodeInserted', this._syncS, false); + this.$element[0] + .removeEventListener('DOMNodeRemoved', this._syncS, false); + } + + this._syncA = null; + this._syncS = null; + + this.$element.off('.select2'); + this.$element.attr('tabindex', this.$element.data('old-tabindex')); + + this.$element.removeClass('select2-hidden-accessible'); + this.$element.attr('aria-hidden', 'false'); + this.$element.removeData('select2'); + + this.dataAdapter.destroy(); + this.selection.destroy(); + this.dropdown.destroy(); + this.results.destroy(); + + this.dataAdapter = null; + this.selection = null; + this.dropdown = null; + this.results = null; + }; + + Select2.prototype.render = function () { + var $container = $( + '' + + '' + + '' + + '' + ); + + $container.attr('dir', this.options.get('dir')); + + this.$container = $container; + + this.$container.addClass('select2-container--' + this.options.get('theme')); + + $container.data('element', this.$element); + + return $container; + }; + + return Select2; +}); + +S2.define('select2/compat/utils',[ + 'jquery' +], function ($) { + function syncCssClasses ($dest, $src, adapter) { + var classes, replacements = [], adapted; + + classes = $.trim($dest.attr('class')); + + if (classes) { + classes = '' + classes; // for IE which returns object + + $(classes.split(/\s+/)).each(function () { + // Save all Select2 classes + if (this.indexOf('select2-') === 0) { + replacements.push(this); + } + }); + } + + classes = $.trim($src.attr('class')); + + if (classes) { + classes = '' + classes; // for IE which returns object + + $(classes.split(/\s+/)).each(function () { + // Only adapt non-Select2 classes + if (this.indexOf('select2-') !== 0) { + adapted = adapter(this); + + if (adapted != null) { + replacements.push(adapted); + } + } + }); + } + + $dest.attr('class', replacements.join(' ')); + } + + return { + syncCssClasses: syncCssClasses + }; +}); + +S2.define('select2/compat/containerCss',[ + 'jquery', + './utils' +], function ($, CompatUtils) { + // No-op CSS adapter that discards all classes by default + function _containerAdapter (clazz) { + return null; + } + + function ContainerCSS () { } + + ContainerCSS.prototype.render = function (decorated) { + var $container = decorated.call(this); + + var containerCssClass = this.options.get('containerCssClass') || ''; + + if ($.isFunction(containerCssClass)) { + containerCssClass = containerCssClass(this.$element); + } + + var containerCssAdapter = this.options.get('adaptContainerCssClass'); + containerCssAdapter = containerCssAdapter || _containerAdapter; + + if (containerCssClass.indexOf(':all:') !== -1) { + containerCssClass = containerCssClass.replace(':all:', ''); + + var _cssAdapter = containerCssAdapter; + + containerCssAdapter = function (clazz) { + var adapted = _cssAdapter(clazz); + + if (adapted != null) { + // Append the old one along with the adapted one + return adapted + ' ' + clazz; + } + + return clazz; + }; + } + + var containerCss = this.options.get('containerCss') || {}; + + if ($.isFunction(containerCss)) { + containerCss = containerCss(this.$element); + } + + CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter); + + $container.css(containerCss); + $container.addClass(containerCssClass); + + return $container; + }; + + return ContainerCSS; +}); + +S2.define('select2/compat/dropdownCss',[ + 'jquery', + './utils' +], function ($, CompatUtils) { + // No-op CSS adapter that discards all classes by default + function _dropdownAdapter (clazz) { + return null; + } + + function DropdownCSS () { } + + DropdownCSS.prototype.render = function (decorated) { + var $dropdown = decorated.call(this); + + var dropdownCssClass = this.options.get('dropdownCssClass') || ''; + + if ($.isFunction(dropdownCssClass)) { + dropdownCssClass = dropdownCssClass(this.$element); + } + + var dropdownCssAdapter = this.options.get('adaptDropdownCssClass'); + dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter; + + if (dropdownCssClass.indexOf(':all:') !== -1) { + dropdownCssClass = dropdownCssClass.replace(':all:', ''); + + var _cssAdapter = dropdownCssAdapter; + + dropdownCssAdapter = function (clazz) { + var adapted = _cssAdapter(clazz); + + if (adapted != null) { + // Append the old one along with the adapted one + return adapted + ' ' + clazz; + } + + return clazz; + }; + } + + var dropdownCss = this.options.get('dropdownCss') || {}; + + if ($.isFunction(dropdownCss)) { + dropdownCss = dropdownCss(this.$element); + } + + CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter); + + $dropdown.css(dropdownCss); + $dropdown.addClass(dropdownCssClass); + + return $dropdown; + }; + + return DropdownCSS; +}); + +S2.define('select2/compat/initSelection',[ + 'jquery' +], function ($) { + function InitSelection (decorated, $element, options) { + if (options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `initSelection` option has been deprecated in favor' + + ' of a custom data adapter that overrides the `current` method. ' + + 'This method is now called multiple times instead of a single ' + + 'time when the instance is initialized. Support will be removed ' + + 'for the `initSelection` option in future versions of Select2' + ); + } + + this.initSelection = options.get('initSelection'); + this._isInitialized = false; + + decorated.call(this, $element, options); + } + + InitSelection.prototype.current = function (decorated, callback) { + var self = this; + + if (this._isInitialized) { + decorated.call(this, callback); + + return; + } + + this.initSelection.call(null, this.$element, function (data) { + self._isInitialized = true; + + if (!$.isArray(data)) { + data = [data]; + } + + callback(data); + }); + }; + + return InitSelection; +}); + +S2.define('select2/compat/inputData',[ + 'jquery' +], function ($) { + function InputData (decorated, $element, options) { + this._currentData = []; + this._valueSeparator = options.get('valueSeparator') || ','; + + if ($element.prop('type') === 'hidden') { + if (options.get('debug') && console && console.warn) { + console.warn( + 'Select2: Using a hidden input with Select2 is no longer ' + + 'supported and may stop working in the future. It is recommended ' + + 'to use a `' + + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + var $rendered = decorated.call(this); + + this._transferTabIndex(); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('open', function () { + self.$search.trigger('focus'); + }); + + container.on('close', function () { + self.$search.val(''); + self.$search.removeAttr('aria-activedescendant'); + self.$search.trigger('focus'); + }); + + container.on('enable', function () { + self.$search.prop('disabled', false); + + self._transferTabIndex(); + }); + + container.on('disable', function () { + self.$search.prop('disabled', true); + }); + + container.on('focus', function (evt) { + self.$search.trigger('focus'); + }); + + container.on('results:focus', function (params) { + self.$search.attr('aria-activedescendant', params.id); + }); + + this.$selection.on('focusin', '.select2-search--inline', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('focusout', '.select2-search--inline', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', '.select2-search--inline', function (evt) { + evt.stopPropagation(); + + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + + var key = evt.which; + + if (key === KEYS.BACKSPACE && self.$search.val() === '') { + var $previousChoice = self.$searchContainer + .prev('.select2-selection__choice'); + + if ($previousChoice.length > 0) { + var item = $previousChoice.data('data'); + + self.searchRemoveChoice(item); + + evt.preventDefault(); + } + } + }); + + // Try to detect the IE version should the `documentMode` property that + // is stored on the document. This is only implemented in IE and is + // slightly cleaner than doing a user agent check. + // This property is not available in Edge, but Edge also doesn't have + // this bug. + var msie = document.documentMode; + var disableInputEvents = msie && msie <= 11; + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$selection.on( + 'input.searchcheck', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents) { + self.$selection.off('input.search input.searchcheck'); + return; + } + + // Unbind the duplicated `keyup` event + self.$selection.off('keyup.search'); + } + ); + + this.$selection.on( + 'keyup.search input.search', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents && evt.type === 'input') { + self.$selection.off('input.search input.searchcheck'); + return; + } + + var key = evt.which; + + // We can freely ignore events from modifier keys + if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) { + return; + } + + // Tabbing will be handled during the `keydown` phase + if (key == KEYS.TAB) { + return; + } + + self.handleSearch(evt); + } + ); + }; + + /** + * This method will transfer the tabindex attribute from the rendered + * selection to the search box. This allows for the search box to be used as + * the primary focus instead of the selection container. + * + * @private + */ + Search.prototype._transferTabIndex = function (decorated) { + this.$search.attr('tabindex', this.$selection.attr('tabindex')); + this.$selection.attr('tabindex', '-1'); + }; + + Search.prototype.createPlaceholder = function (decorated, placeholder) { + this.$search.attr('placeholder', placeholder.text); + }; + + Search.prototype.update = function (decorated, data) { + var searchHadFocus = this.$search[0] == document.activeElement; + + this.$search.attr('placeholder', ''); + + decorated.call(this, data); + + this.$selection.find('.select2-selection__rendered') + .append(this.$searchContainer); + + this.resizeSearch(); + if (searchHadFocus) { + this.$search.focus(); + } + }; + + Search.prototype.handleSearch = function () { + this.resizeSearch(); + + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.searchRemoveChoice = function (decorated, item) { + this.trigger('unselect', { + data: item + }); + + this.$search.val(item.text); + this.handleSearch(); + }; + + Search.prototype.resizeSearch = function () { + this.$search.css('width', '25px'); + + var width = ''; + + if (this.$search.attr('placeholder') !== '') { + width = this.$selection.find('.select2-selection__rendered').innerWidth(); + } else { + var minimumWidth = this.$search.val().length + 1; + + width = (minimumWidth * 0.75) + 'em'; + } + + this.$search.css('width', width); + }; + + return Search; +}); + +S2.define('select2/selection/eventRelay',[ + 'jquery' +], function ($) { + function EventRelay () { } + + EventRelay.prototype.bind = function (decorated, container, $container) { + var self = this; + var relayEvents = [ + 'open', 'opening', + 'close', 'closing', + 'select', 'selecting', + 'unselect', 'unselecting' + ]; + + var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; + + decorated.call(this, container, $container); + + container.on('*', function (name, params) { + // Ignore events that should not be relayed + if ($.inArray(name, relayEvents) === -1) { + return; + } + + // The parameters should always be an object + params = params || {}; + + // Generate the jQuery event for the Select2 event + var evt = $.Event('select2:' + name, { + params: params + }); + + self.$element.trigger(evt); + + // Only handle preventable events if it was one + if ($.inArray(name, preventableEvents) === -1) { + return; + } + + params.prevented = evt.isDefaultPrevented(); + }); + }; + + return EventRelay; +}); + +S2.define('select2/translation',[ + 'jquery', + 'require' +], function ($, require) { + function Translation (dict) { + this.dict = dict || {}; + } + + Translation.prototype.all = function () { + return this.dict; + }; + + Translation.prototype.get = function (key) { + return this.dict[key]; + }; + + Translation.prototype.extend = function (translation) { + this.dict = $.extend({}, translation.all(), this.dict); + }; + + // Static functions + + Translation._cache = {}; + + Translation.loadPath = function (path) { + if (!(path in Translation._cache)) { + var translations = require(path); + + Translation._cache[path] = translations; + } + + return new Translation(Translation._cache[path]); + }; + + return Translation; +}); + +S2.define('select2/diacritics',[ + +], function () { + var diacritics = { + '\u24B6': 'A', + '\uFF21': 'A', + '\u00C0': 'A', + '\u00C1': 'A', + '\u00C2': 'A', + '\u1EA6': 'A', + '\u1EA4': 'A', + '\u1EAA': 'A', + '\u1EA8': 'A', + '\u00C3': 'A', + '\u0100': 'A', + '\u0102': 'A', + '\u1EB0': 'A', + '\u1EAE': 'A', + '\u1EB4': 'A', + '\u1EB2': 'A', + '\u0226': 'A', + '\u01E0': 'A', + '\u00C4': 'A', + '\u01DE': 'A', + '\u1EA2': 'A', + '\u00C5': 'A', + '\u01FA': 'A', + '\u01CD': 'A', + '\u0200': 'A', + '\u0202': 'A', + '\u1EA0': 'A', + '\u1EAC': 'A', + '\u1EB6': 'A', + '\u1E00': 'A', + '\u0104': 'A', + '\u023A': 'A', + '\u2C6F': 'A', + '\uA732': 'AA', + '\u00C6': 'AE', + '\u01FC': 'AE', + '\u01E2': 'AE', + '\uA734': 'AO', + '\uA736': 'AU', + '\uA738': 'AV', + '\uA73A': 'AV', + '\uA73C': 'AY', + '\u24B7': 'B', + '\uFF22': 'B', + '\u1E02': 'B', + '\u1E04': 'B', + '\u1E06': 'B', + '\u0243': 'B', + '\u0182': 'B', + '\u0181': 'B', + '\u24B8': 'C', + '\uFF23': 'C', + '\u0106': 'C', + '\u0108': 'C', + '\u010A': 'C', + '\u010C': 'C', + '\u00C7': 'C', + '\u1E08': 'C', + '\u0187': 'C', + '\u023B': 'C', + '\uA73E': 'C', + '\u24B9': 'D', + '\uFF24': 'D', + '\u1E0A': 'D', + '\u010E': 'D', + '\u1E0C': 'D', + '\u1E10': 'D', + '\u1E12': 'D', + '\u1E0E': 'D', + '\u0110': 'D', + '\u018B': 'D', + '\u018A': 'D', + '\u0189': 'D', + '\uA779': 'D', + '\u01F1': 'DZ', + '\u01C4': 'DZ', + '\u01F2': 'Dz', + '\u01C5': 'Dz', + '\u24BA': 'E', + '\uFF25': 'E', + '\u00C8': 'E', + '\u00C9': 'E', + '\u00CA': 'E', + '\u1EC0': 'E', + '\u1EBE': 'E', + '\u1EC4': 'E', + '\u1EC2': 'E', + '\u1EBC': 'E', + '\u0112': 'E', + '\u1E14': 'E', + '\u1E16': 'E', + '\u0114': 'E', + '\u0116': 'E', + '\u00CB': 'E', + '\u1EBA': 'E', + '\u011A': 'E', + '\u0204': 'E', + '\u0206': 'E', + '\u1EB8': 'E', + '\u1EC6': 'E', + '\u0228': 'E', + '\u1E1C': 'E', + '\u0118': 'E', + '\u1E18': 'E', + '\u1E1A': 'E', + '\u0190': 'E', + '\u018E': 'E', + '\u24BB': 'F', + '\uFF26': 'F', + '\u1E1E': 'F', + '\u0191': 'F', + '\uA77B': 'F', + '\u24BC': 'G', + '\uFF27': 'G', + '\u01F4': 'G', + '\u011C': 'G', + '\u1E20': 'G', + '\u011E': 'G', + '\u0120': 'G', + '\u01E6': 'G', + '\u0122': 'G', + '\u01E4': 'G', + '\u0193': 'G', + '\uA7A0': 'G', + '\uA77D': 'G', + '\uA77E': 'G', + '\u24BD': 'H', + '\uFF28': 'H', + '\u0124': 'H', + '\u1E22': 'H', + '\u1E26': 'H', + '\u021E': 'H', + '\u1E24': 'H', + '\u1E28': 'H', + '\u1E2A': 'H', + '\u0126': 'H', + '\u2C67': 'H', + '\u2C75': 'H', + '\uA78D': 'H', + '\u24BE': 'I', + '\uFF29': 'I', + '\u00CC': 'I', + '\u00CD': 'I', + '\u00CE': 'I', + '\u0128': 'I', + '\u012A': 'I', + '\u012C': 'I', + '\u0130': 'I', + '\u00CF': 'I', + '\u1E2E': 'I', + '\u1EC8': 'I', + '\u01CF': 'I', + '\u0208': 'I', + '\u020A': 'I', + '\u1ECA': 'I', + '\u012E': 'I', + '\u1E2C': 'I', + '\u0197': 'I', + '\u24BF': 'J', + '\uFF2A': 'J', + '\u0134': 'J', + '\u0248': 'J', + '\u24C0': 'K', + '\uFF2B': 'K', + '\u1E30': 'K', + '\u01E8': 'K', + '\u1E32': 'K', + '\u0136': 'K', + '\u1E34': 'K', + '\u0198': 'K', + '\u2C69': 'K', + '\uA740': 'K', + '\uA742': 'K', + '\uA744': 'K', + '\uA7A2': 'K', + '\u24C1': 'L', + '\uFF2C': 'L', + '\u013F': 'L', + '\u0139': 'L', + '\u013D': 'L', + '\u1E36': 'L', + '\u1E38': 'L', + '\u013B': 'L', + '\u1E3C': 'L', + '\u1E3A': 'L', + '\u0141': 'L', + '\u023D': 'L', + '\u2C62': 'L', + '\u2C60': 'L', + '\uA748': 'L', + '\uA746': 'L', + '\uA780': 'L', + '\u01C7': 'LJ', + '\u01C8': 'Lj', + '\u24C2': 'M', + '\uFF2D': 'M', + '\u1E3E': 'M', + '\u1E40': 'M', + '\u1E42': 'M', + '\u2C6E': 'M', + '\u019C': 'M', + '\u24C3': 'N', + '\uFF2E': 'N', + '\u01F8': 'N', + '\u0143': 'N', + '\u00D1': 'N', + '\u1E44': 'N', + '\u0147': 'N', + '\u1E46': 'N', + '\u0145': 'N', + '\u1E4A': 'N', + '\u1E48': 'N', + '\u0220': 'N', + '\u019D': 'N', + '\uA790': 'N', + '\uA7A4': 'N', + '\u01CA': 'NJ', + '\u01CB': 'Nj', + '\u24C4': 'O', + '\uFF2F': 'O', + '\u00D2': 'O', + '\u00D3': 'O', + '\u00D4': 'O', + '\u1ED2': 'O', + '\u1ED0': 'O', + '\u1ED6': 'O', + '\u1ED4': 'O', + '\u00D5': 'O', + '\u1E4C': 'O', + '\u022C': 'O', + '\u1E4E': 'O', + '\u014C': 'O', + '\u1E50': 'O', + '\u1E52': 'O', + '\u014E': 'O', + '\u022E': 'O', + '\u0230': 'O', + '\u00D6': 'O', + '\u022A': 'O', + '\u1ECE': 'O', + '\u0150': 'O', + '\u01D1': 'O', + '\u020C': 'O', + '\u020E': 'O', + '\u01A0': 'O', + '\u1EDC': 'O', + '\u1EDA': 'O', + '\u1EE0': 'O', + '\u1EDE': 'O', + '\u1EE2': 'O', + '\u1ECC': 'O', + '\u1ED8': 'O', + '\u01EA': 'O', + '\u01EC': 'O', + '\u00D8': 'O', + '\u01FE': 'O', + '\u0186': 'O', + '\u019F': 'O', + '\uA74A': 'O', + '\uA74C': 'O', + '\u01A2': 'OI', + '\uA74E': 'OO', + '\u0222': 'OU', + '\u24C5': 'P', + '\uFF30': 'P', + '\u1E54': 'P', + '\u1E56': 'P', + '\u01A4': 'P', + '\u2C63': 'P', + '\uA750': 'P', + '\uA752': 'P', + '\uA754': 'P', + '\u24C6': 'Q', + '\uFF31': 'Q', + '\uA756': 'Q', + '\uA758': 'Q', + '\u024A': 'Q', + '\u24C7': 'R', + '\uFF32': 'R', + '\u0154': 'R', + '\u1E58': 'R', + '\u0158': 'R', + '\u0210': 'R', + '\u0212': 'R', + '\u1E5A': 'R', + '\u1E5C': 'R', + '\u0156': 'R', + '\u1E5E': 'R', + '\u024C': 'R', + '\u2C64': 'R', + '\uA75A': 'R', + '\uA7A6': 'R', + '\uA782': 'R', + '\u24C8': 'S', + '\uFF33': 'S', + '\u1E9E': 'S', + '\u015A': 'S', + '\u1E64': 'S', + '\u015C': 'S', + '\u1E60': 'S', + '\u0160': 'S', + '\u1E66': 'S', + '\u1E62': 'S', + '\u1E68': 'S', + '\u0218': 'S', + '\u015E': 'S', + '\u2C7E': 'S', + '\uA7A8': 'S', + '\uA784': 'S', + '\u24C9': 'T', + '\uFF34': 'T', + '\u1E6A': 'T', + '\u0164': 'T', + '\u1E6C': 'T', + '\u021A': 'T', + '\u0162': 'T', + '\u1E70': 'T', + '\u1E6E': 'T', + '\u0166': 'T', + '\u01AC': 'T', + '\u01AE': 'T', + '\u023E': 'T', + '\uA786': 'T', + '\uA728': 'TZ', + '\u24CA': 'U', + '\uFF35': 'U', + '\u00D9': 'U', + '\u00DA': 'U', + '\u00DB': 'U', + '\u0168': 'U', + '\u1E78': 'U', + '\u016A': 'U', + '\u1E7A': 'U', + '\u016C': 'U', + '\u00DC': 'U', + '\u01DB': 'U', + '\u01D7': 'U', + '\u01D5': 'U', + '\u01D9': 'U', + '\u1EE6': 'U', + '\u016E': 'U', + '\u0170': 'U', + '\u01D3': 'U', + '\u0214': 'U', + '\u0216': 'U', + '\u01AF': 'U', + '\u1EEA': 'U', + '\u1EE8': 'U', + '\u1EEE': 'U', + '\u1EEC': 'U', + '\u1EF0': 'U', + '\u1EE4': 'U', + '\u1E72': 'U', + '\u0172': 'U', + '\u1E76': 'U', + '\u1E74': 'U', + '\u0244': 'U', + '\u24CB': 'V', + '\uFF36': 'V', + '\u1E7C': 'V', + '\u1E7E': 'V', + '\u01B2': 'V', + '\uA75E': 'V', + '\u0245': 'V', + '\uA760': 'VY', + '\u24CC': 'W', + '\uFF37': 'W', + '\u1E80': 'W', + '\u1E82': 'W', + '\u0174': 'W', + '\u1E86': 'W', + '\u1E84': 'W', + '\u1E88': 'W', + '\u2C72': 'W', + '\u24CD': 'X', + '\uFF38': 'X', + '\u1E8A': 'X', + '\u1E8C': 'X', + '\u24CE': 'Y', + '\uFF39': 'Y', + '\u1EF2': 'Y', + '\u00DD': 'Y', + '\u0176': 'Y', + '\u1EF8': 'Y', + '\u0232': 'Y', + '\u1E8E': 'Y', + '\u0178': 'Y', + '\u1EF6': 'Y', + '\u1EF4': 'Y', + '\u01B3': 'Y', + '\u024E': 'Y', + '\u1EFE': 'Y', + '\u24CF': 'Z', + '\uFF3A': 'Z', + '\u0179': 'Z', + '\u1E90': 'Z', + '\u017B': 'Z', + '\u017D': 'Z', + '\u1E92': 'Z', + '\u1E94': 'Z', + '\u01B5': 'Z', + '\u0224': 'Z', + '\u2C7F': 'Z', + '\u2C6B': 'Z', + '\uA762': 'Z', + '\u24D0': 'a', + '\uFF41': 'a', + '\u1E9A': 'a', + '\u00E0': 'a', + '\u00E1': 'a', + '\u00E2': 'a', + '\u1EA7': 'a', + '\u1EA5': 'a', + '\u1EAB': 'a', + '\u1EA9': 'a', + '\u00E3': 'a', + '\u0101': 'a', + '\u0103': 'a', + '\u1EB1': 'a', + '\u1EAF': 'a', + '\u1EB5': 'a', + '\u1EB3': 'a', + '\u0227': 'a', + '\u01E1': 'a', + '\u00E4': 'a', + '\u01DF': 'a', + '\u1EA3': 'a', + '\u00E5': 'a', + '\u01FB': 'a', + '\u01CE': 'a', + '\u0201': 'a', + '\u0203': 'a', + '\u1EA1': 'a', + '\u1EAD': 'a', + '\u1EB7': 'a', + '\u1E01': 'a', + '\u0105': 'a', + '\u2C65': 'a', + '\u0250': 'a', + '\uA733': 'aa', + '\u00E6': 'ae', + '\u01FD': 'ae', + '\u01E3': 'ae', + '\uA735': 'ao', + '\uA737': 'au', + '\uA739': 'av', + '\uA73B': 'av', + '\uA73D': 'ay', + '\u24D1': 'b', + '\uFF42': 'b', + '\u1E03': 'b', + '\u1E05': 'b', + '\u1E07': 'b', + '\u0180': 'b', + '\u0183': 'b', + '\u0253': 'b', + '\u24D2': 'c', + '\uFF43': 'c', + '\u0107': 'c', + '\u0109': 'c', + '\u010B': 'c', + '\u010D': 'c', + '\u00E7': 'c', + '\u1E09': 'c', + '\u0188': 'c', + '\u023C': 'c', + '\uA73F': 'c', + '\u2184': 'c', + '\u24D3': 'd', + '\uFF44': 'd', + '\u1E0B': 'd', + '\u010F': 'd', + '\u1E0D': 'd', + '\u1E11': 'd', + '\u1E13': 'd', + '\u1E0F': 'd', + '\u0111': 'd', + '\u018C': 'd', + '\u0256': 'd', + '\u0257': 'd', + '\uA77A': 'd', + '\u01F3': 'dz', + '\u01C6': 'dz', + '\u24D4': 'e', + '\uFF45': 'e', + '\u00E8': 'e', + '\u00E9': 'e', + '\u00EA': 'e', + '\u1EC1': 'e', + '\u1EBF': 'e', + '\u1EC5': 'e', + '\u1EC3': 'e', + '\u1EBD': 'e', + '\u0113': 'e', + '\u1E15': 'e', + '\u1E17': 'e', + '\u0115': 'e', + '\u0117': 'e', + '\u00EB': 'e', + '\u1EBB': 'e', + '\u011B': 'e', + '\u0205': 'e', + '\u0207': 'e', + '\u1EB9': 'e', + '\u1EC7': 'e', + '\u0229': 'e', + '\u1E1D': 'e', + '\u0119': 'e', + '\u1E19': 'e', + '\u1E1B': 'e', + '\u0247': 'e', + '\u025B': 'e', + '\u01DD': 'e', + '\u24D5': 'f', + '\uFF46': 'f', + '\u1E1F': 'f', + '\u0192': 'f', + '\uA77C': 'f', + '\u24D6': 'g', + '\uFF47': 'g', + '\u01F5': 'g', + '\u011D': 'g', + '\u1E21': 'g', + '\u011F': 'g', + '\u0121': 'g', + '\u01E7': 'g', + '\u0123': 'g', + '\u01E5': 'g', + '\u0260': 'g', + '\uA7A1': 'g', + '\u1D79': 'g', + '\uA77F': 'g', + '\u24D7': 'h', + '\uFF48': 'h', + '\u0125': 'h', + '\u1E23': 'h', + '\u1E27': 'h', + '\u021F': 'h', + '\u1E25': 'h', + '\u1E29': 'h', + '\u1E2B': 'h', + '\u1E96': 'h', + '\u0127': 'h', + '\u2C68': 'h', + '\u2C76': 'h', + '\u0265': 'h', + '\u0195': 'hv', + '\u24D8': 'i', + '\uFF49': 'i', + '\u00EC': 'i', + '\u00ED': 'i', + '\u00EE': 'i', + '\u0129': 'i', + '\u012B': 'i', + '\u012D': 'i', + '\u00EF': 'i', + '\u1E2F': 'i', + '\u1EC9': 'i', + '\u01D0': 'i', + '\u0209': 'i', + '\u020B': 'i', + '\u1ECB': 'i', + '\u012F': 'i', + '\u1E2D': 'i', + '\u0268': 'i', + '\u0131': 'i', + '\u24D9': 'j', + '\uFF4A': 'j', + '\u0135': 'j', + '\u01F0': 'j', + '\u0249': 'j', + '\u24DA': 'k', + '\uFF4B': 'k', + '\u1E31': 'k', + '\u01E9': 'k', + '\u1E33': 'k', + '\u0137': 'k', + '\u1E35': 'k', + '\u0199': 'k', + '\u2C6A': 'k', + '\uA741': 'k', + '\uA743': 'k', + '\uA745': 'k', + '\uA7A3': 'k', + '\u24DB': 'l', + '\uFF4C': 'l', + '\u0140': 'l', + '\u013A': 'l', + '\u013E': 'l', + '\u1E37': 'l', + '\u1E39': 'l', + '\u013C': 'l', + '\u1E3D': 'l', + '\u1E3B': 'l', + '\u017F': 'l', + '\u0142': 'l', + '\u019A': 'l', + '\u026B': 'l', + '\u2C61': 'l', + '\uA749': 'l', + '\uA781': 'l', + '\uA747': 'l', + '\u01C9': 'lj', + '\u24DC': 'm', + '\uFF4D': 'm', + '\u1E3F': 'm', + '\u1E41': 'm', + '\u1E43': 'm', + '\u0271': 'm', + '\u026F': 'm', + '\u24DD': 'n', + '\uFF4E': 'n', + '\u01F9': 'n', + '\u0144': 'n', + '\u00F1': 'n', + '\u1E45': 'n', + '\u0148': 'n', + '\u1E47': 'n', + '\u0146': 'n', + '\u1E4B': 'n', + '\u1E49': 'n', + '\u019E': 'n', + '\u0272': 'n', + '\u0149': 'n', + '\uA791': 'n', + '\uA7A5': 'n', + '\u01CC': 'nj', + '\u24DE': 'o', + '\uFF4F': 'o', + '\u00F2': 'o', + '\u00F3': 'o', + '\u00F4': 'o', + '\u1ED3': 'o', + '\u1ED1': 'o', + '\u1ED7': 'o', + '\u1ED5': 'o', + '\u00F5': 'o', + '\u1E4D': 'o', + '\u022D': 'o', + '\u1E4F': 'o', + '\u014D': 'o', + '\u1E51': 'o', + '\u1E53': 'o', + '\u014F': 'o', + '\u022F': 'o', + '\u0231': 'o', + '\u00F6': 'o', + '\u022B': 'o', + '\u1ECF': 'o', + '\u0151': 'o', + '\u01D2': 'o', + '\u020D': 'o', + '\u020F': 'o', + '\u01A1': 'o', + '\u1EDD': 'o', + '\u1EDB': 'o', + '\u1EE1': 'o', + '\u1EDF': 'o', + '\u1EE3': 'o', + '\u1ECD': 'o', + '\u1ED9': 'o', + '\u01EB': 'o', + '\u01ED': 'o', + '\u00F8': 'o', + '\u01FF': 'o', + '\u0254': 'o', + '\uA74B': 'o', + '\uA74D': 'o', + '\u0275': 'o', + '\u01A3': 'oi', + '\u0223': 'ou', + '\uA74F': 'oo', + '\u24DF': 'p', + '\uFF50': 'p', + '\u1E55': 'p', + '\u1E57': 'p', + '\u01A5': 'p', + '\u1D7D': 'p', + '\uA751': 'p', + '\uA753': 'p', + '\uA755': 'p', + '\u24E0': 'q', + '\uFF51': 'q', + '\u024B': 'q', + '\uA757': 'q', + '\uA759': 'q', + '\u24E1': 'r', + '\uFF52': 'r', + '\u0155': 'r', + '\u1E59': 'r', + '\u0159': 'r', + '\u0211': 'r', + '\u0213': 'r', + '\u1E5B': 'r', + '\u1E5D': 'r', + '\u0157': 'r', + '\u1E5F': 'r', + '\u024D': 'r', + '\u027D': 'r', + '\uA75B': 'r', + '\uA7A7': 'r', + '\uA783': 'r', + '\u24E2': 's', + '\uFF53': 's', + '\u00DF': 's', + '\u015B': 's', + '\u1E65': 's', + '\u015D': 's', + '\u1E61': 's', + '\u0161': 's', + '\u1E67': 's', + '\u1E63': 's', + '\u1E69': 's', + '\u0219': 's', + '\u015F': 's', + '\u023F': 's', + '\uA7A9': 's', + '\uA785': 's', + '\u1E9B': 's', + '\u24E3': 't', + '\uFF54': 't', + '\u1E6B': 't', + '\u1E97': 't', + '\u0165': 't', + '\u1E6D': 't', + '\u021B': 't', + '\u0163': 't', + '\u1E71': 't', + '\u1E6F': 't', + '\u0167': 't', + '\u01AD': 't', + '\u0288': 't', + '\u2C66': 't', + '\uA787': 't', + '\uA729': 'tz', + '\u24E4': 'u', + '\uFF55': 'u', + '\u00F9': 'u', + '\u00FA': 'u', + '\u00FB': 'u', + '\u0169': 'u', + '\u1E79': 'u', + '\u016B': 'u', + '\u1E7B': 'u', + '\u016D': 'u', + '\u00FC': 'u', + '\u01DC': 'u', + '\u01D8': 'u', + '\u01D6': 'u', + '\u01DA': 'u', + '\u1EE7': 'u', + '\u016F': 'u', + '\u0171': 'u', + '\u01D4': 'u', + '\u0215': 'u', + '\u0217': 'u', + '\u01B0': 'u', + '\u1EEB': 'u', + '\u1EE9': 'u', + '\u1EEF': 'u', + '\u1EED': 'u', + '\u1EF1': 'u', + '\u1EE5': 'u', + '\u1E73': 'u', + '\u0173': 'u', + '\u1E77': 'u', + '\u1E75': 'u', + '\u0289': 'u', + '\u24E5': 'v', + '\uFF56': 'v', + '\u1E7D': 'v', + '\u1E7F': 'v', + '\u028B': 'v', + '\uA75F': 'v', + '\u028C': 'v', + '\uA761': 'vy', + '\u24E6': 'w', + '\uFF57': 'w', + '\u1E81': 'w', + '\u1E83': 'w', + '\u0175': 'w', + '\u1E87': 'w', + '\u1E85': 'w', + '\u1E98': 'w', + '\u1E89': 'w', + '\u2C73': 'w', + '\u24E7': 'x', + '\uFF58': 'x', + '\u1E8B': 'x', + '\u1E8D': 'x', + '\u24E8': 'y', + '\uFF59': 'y', + '\u1EF3': 'y', + '\u00FD': 'y', + '\u0177': 'y', + '\u1EF9': 'y', + '\u0233': 'y', + '\u1E8F': 'y', + '\u00FF': 'y', + '\u1EF7': 'y', + '\u1E99': 'y', + '\u1EF5': 'y', + '\u01B4': 'y', + '\u024F': 'y', + '\u1EFF': 'y', + '\u24E9': 'z', + '\uFF5A': 'z', + '\u017A': 'z', + '\u1E91': 'z', + '\u017C': 'z', + '\u017E': 'z', + '\u1E93': 'z', + '\u1E95': 'z', + '\u01B6': 'z', + '\u0225': 'z', + '\u0240': 'z', + '\u2C6C': 'z', + '\uA763': 'z', + '\u0386': '\u0391', + '\u0388': '\u0395', + '\u0389': '\u0397', + '\u038A': '\u0399', + '\u03AA': '\u0399', + '\u038C': '\u039F', + '\u038E': '\u03A5', + '\u03AB': '\u03A5', + '\u038F': '\u03A9', + '\u03AC': '\u03B1', + '\u03AD': '\u03B5', + '\u03AE': '\u03B7', + '\u03AF': '\u03B9', + '\u03CA': '\u03B9', + '\u0390': '\u03B9', + '\u03CC': '\u03BF', + '\u03CD': '\u03C5', + '\u03CB': '\u03C5', + '\u03B0': '\u03C5', + '\u03C9': '\u03C9', + '\u03C2': '\u03C3' + }; + + return diacritics; +}); + +S2.define('select2/data/base',[ + '../utils' +], function (Utils) { + function BaseAdapter ($element, options) { + BaseAdapter.__super__.constructor.call(this); + } + + Utils.Extend(BaseAdapter, Utils.Observable); + + BaseAdapter.prototype.current = function (callback) { + throw new Error('The `current` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.query = function (params, callback) { + throw new Error('The `query` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.bind = function (container, $container) { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.destroy = function () { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.generateResultId = function (container, data) { + var id = container.id + '-result-'; + + id += Utils.generateChars(4); + + if (data.id != null) { + id += '-' + data.id.toString(); + } else { + id += '-' + Utils.generateChars(4); + } + return id; + }; + + return BaseAdapter; +}); + +S2.define('select2/data/select',[ + './base', + '../utils', + 'jquery' +], function (BaseAdapter, Utils, $) { + function SelectAdapter ($element, options) { + this.$element = $element; + this.options = options; + + SelectAdapter.__super__.constructor.call(this); + } + + Utils.Extend(SelectAdapter, BaseAdapter); + + SelectAdapter.prototype.current = function (callback) { + var data = []; + var self = this; + + this.$element.find(':selected').each(function () { + var $option = $(this); + + var option = self.item($option); + + data.push(option); + }); + + callback(data); + }; + + SelectAdapter.prototype.select = function (data) { + var self = this; + + data.selected = true; + + // If data.element is a DOM node, use it instead + if ($(data.element).is('option')) { + data.element.selected = true; + + this.$element.trigger('change'); + + return; + } + + if (this.$element.prop('multiple')) { + this.current(function (currentData) { + var val = []; + + data = [data]; + data.push.apply(data, currentData); + + for (var d = 0; d < data.length; d++) { + var id = data[d].id; + + if ($.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + self.$element.trigger('change'); + }); + } else { + var val = data.id; + + this.$element.val(val); + this.$element.trigger('change'); + } + }; + + SelectAdapter.prototype.unselect = function (data) { + var self = this; + + if (!this.$element.prop('multiple')) { + return; + } + + data.selected = false; + + if ($(data.element).is('option')) { + data.element.selected = false; + + this.$element.trigger('change'); + + return; + } + + this.current(function (currentData) { + var val = []; + + for (var d = 0; d < currentData.length; d++) { + var id = currentData[d].id; + + if (id !== data.id && $.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + + self.$element.trigger('change'); + }); + }; + + SelectAdapter.prototype.bind = function (container, $container) { + var self = this; + + this.container = container; + + container.on('select', function (params) { + self.select(params.data); + }); + + container.on('unselect', function (params) { + self.unselect(params.data); + }); + }; + + SelectAdapter.prototype.destroy = function () { + // Remove anything added to child elements + this.$element.find('*').each(function () { + // Remove any custom data set by Select2 + $.removeData(this, 'data'); + }); + }; + + SelectAdapter.prototype.query = function (params, callback) { + var data = []; + var self = this; + + var $options = this.$element.children(); + + $options.each(function () { + var $option = $(this); + + if (!$option.is('option') && !$option.is('optgroup')) { + return; + } + + var option = self.item($option); + + var matches = self.matches(params, option); + + if (matches !== null) { + data.push(matches); + } + }); + + callback({ + results: data + }); + }; + + SelectAdapter.prototype.addOptions = function ($options) { + Utils.appendMany(this.$element, $options); + }; + + SelectAdapter.prototype.option = function (data) { + var option; + + if (data.children) { + option = document.createElement('optgroup'); + option.label = data.text; + } else { + option = document.createElement('option'); + + if (option.textContent !== undefined) { + option.textContent = data.text; + } else { + option.innerText = data.text; + } + } + + if (data.id) { + option.value = data.id; + } + + if (data.disabled) { + option.disabled = true; + } + + if (data.selected) { + option.selected = true; + } + + if (data.title) { + option.title = data.title; + } + + var $option = $(option); + + var normalizedData = this._normalizeItem(data); + normalizedData.element = option; + + // Override the option's data with the combined data + $.data(option, 'data', normalizedData); + + return $option; + }; + + SelectAdapter.prototype.item = function ($option) { + var data = {}; + + data = $.data($option[0], 'data'); + + if (data != null) { + return data; + } + + if ($option.is('option')) { + data = { + id: $option.val(), + text: $option.text(), + disabled: $option.prop('disabled'), + selected: $option.prop('selected'), + title: $option.prop('title') + }; + } else if ($option.is('optgroup')) { + data = { + text: $option.prop('label'), + children: [], + title: $option.prop('title') + }; + + var $children = $option.children('option'); + var children = []; + + for (var c = 0; c < $children.length; c++) { + var $child = $($children[c]); + + var child = this.item($child); + + children.push(child); + } + + data.children = children; + } + + data = this._normalizeItem(data); + data.element = $option[0]; + + $.data($option[0], 'data', data); + + return data; + }; + + SelectAdapter.prototype._normalizeItem = function (item) { + if (!$.isPlainObject(item)) { + item = { + id: item, + text: item + }; + } + + item = $.extend({}, { + text: '' + }, item); + + var defaults = { + selected: false, + disabled: false + }; + + if (item.id != null) { + item.id = item.id.toString(); + } + + if (item.text != null) { + item.text = item.text.toString(); + } + + if (item._resultId == null && item.id && this.container != null) { + item._resultId = this.generateResultId(this.container, item); + } + + return $.extend({}, defaults, item); + }; + + SelectAdapter.prototype.matches = function (params, data) { + var matcher = this.options.get('matcher'); + + return matcher(params, data); + }; + + return SelectAdapter; +}); + +S2.define('select2/data/array',[ + './select', + '../utils', + 'jquery' +], function (SelectAdapter, Utils, $) { + function ArrayAdapter ($element, options) { + var data = options.get('data') || []; + + ArrayAdapter.__super__.constructor.call(this, $element, options); + + this.addOptions(this.convertToOptions(data)); + } + + Utils.Extend(ArrayAdapter, SelectAdapter); + + ArrayAdapter.prototype.select = function (data) { + var $option = this.$element.find('option').filter(function (i, elm) { + return elm.value == data.id.toString(); + }); + + if ($option.length === 0) { + $option = this.option(data); + + this.addOptions($option); + } + + ArrayAdapter.__super__.select.call(this, data); + }; + + ArrayAdapter.prototype.convertToOptions = function (data) { + var self = this; + + var $existing = this.$element.find('option'); + var existingIds = $existing.map(function () { + return self.item($(this)).id; + }).get(); + + var $options = []; + + // Filter out all items except for the one passed in the argument + function onlyItem (item) { + return function () { + return $(this).val() == item.id; + }; + } + + for (var d = 0; d < data.length; d++) { + var item = this._normalizeItem(data[d]); + + // Skip items which were pre-loaded, only merge the data + if ($.inArray(item.id, existingIds) >= 0) { + var $existingOption = $existing.filter(onlyItem(item)); + + var existingData = this.item($existingOption); + var newData = $.extend(true, {}, item, existingData); + + var $newOption = this.option(newData); + + $existingOption.replaceWith($newOption); + + continue; + } + + var $option = this.option(item); + + if (item.children) { + var $children = this.convertToOptions(item.children); + + Utils.appendMany($option, $children); + } + + $options.push($option); + } + + return $options; + }; + + return ArrayAdapter; +}); + +S2.define('select2/data/ajax',[ + './array', + '../utils', + 'jquery' +], function (ArrayAdapter, Utils, $) { + function AjaxAdapter ($element, options) { + this.ajaxOptions = this._applyDefaults(options.get('ajax')); + + if (this.ajaxOptions.processResults != null) { + this.processResults = this.ajaxOptions.processResults; + } + + AjaxAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(AjaxAdapter, ArrayAdapter); + + AjaxAdapter.prototype._applyDefaults = function (options) { + var defaults = { + data: function (params) { + return $.extend({}, params, { + q: params.term + }); + }, + transport: function (params, success, failure) { + var $request = $.ajax(params); + + $request.then(success); + $request.fail(failure); + + return $request; + } + }; + + return $.extend({}, defaults, options, true); + }; + + AjaxAdapter.prototype.processResults = function (results) { + return results; + }; + + AjaxAdapter.prototype.query = function (params, callback) { + var matches = []; + var self = this; + + if (this._request != null) { + // JSONP requests cannot always be aborted + if ($.isFunction(this._request.abort)) { + this._request.abort(); + } + + this._request = null; + } + + var options = $.extend({ + type: 'GET' + }, this.ajaxOptions); + + if (typeof options.url === 'function') { + options.url = options.url.call(this.$element, params); + } + + if (typeof options.data === 'function') { + options.data = options.data.call(this.$element, params); + } + + function request () { + var $request = options.transport(options, function (data) { + var results = self.processResults(data, params); + + if (self.options.get('debug') && window.console && console.error) { + // Check to make sure that the response included a `results` key. + if (!results || !results.results || !$.isArray(results.results)) { + console.error( + 'Select2: The AJAX results did not return an array in the ' + + '`results` key of the response.' + ); + } + } + + callback(results); + }, function () { + // Attempt to detect if a request was aborted + // Only works if the transport exposes a status property + if ($request.status && $request.status === '0') { + return; + } + + self.trigger('results:message', { + message: 'errorLoading' + }); + }); + + self._request = $request; + } + + if (this.ajaxOptions.delay && params.term != null) { + if (this._queryTimeout) { + window.clearTimeout(this._queryTimeout); + } + + this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay); + } else { + request(); + } + }; + + return AjaxAdapter; +}); + +S2.define('select2/data/tags',[ + 'jquery' +], function ($) { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + var createTag = options.get('createTag'); + + if (createTag !== undefined) { + this.createTag = createTag; + } + + var insertTag = options.get('insertTag'); + + if (insertTag !== undefined) { + this.insertTag = insertTag; + } + + decorated.call(this, $element, options); + + if ($.isArray(tags)) { + for (var t = 0; t < tags.length; t++) { + var tag = tags[t]; + var item = this._normalizeItem(tag); + + var $option = this.option(item); + + this.$element.append($option); + } + } + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + this._removeOldTags(); + + if (params.term == null || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (obj, child) { + var data = obj.results; + + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && + !wrapper({ + results: option.children + }, true) + ); + + var checkText = option.text === params.term; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + obj.data = data; + callback(obj); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + + if (tag != null) { + var $option = self.option(tag); + $option.attr('data-select2-tag', true); + + self.addOptions([$option]); + + self.insertTag(data, tag); + } + + obj.results = data; + + callback(obj); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + var term = $.trim(params.term); + + if (term === '') { + return null; + } + + return { + id: term, + text: term + }; + }; + + Tags.prototype.insertTag = function (_, data, tag) { + data.unshift(tag); + }; + + Tags.prototype._removeOldTags = function (_) { + var tag = this._lastTag; + + var $options = this.$element.find('option[data-select2-tag]'); + + $options.each(function () { + if (this.selected) { + return; + } + + $(this).remove(); + }); + }; + + return Tags; +}); + +S2.define('select2/data/tokenizer',[ + 'jquery' +], function ($) { + function Tokenizer (decorated, $element, options) { + var tokenizer = options.get('tokenizer'); + + if (tokenizer !== undefined) { + this.tokenizer = tokenizer; + } + + decorated.call(this, $element, options); + } + + Tokenizer.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); + + this.$search = container.dropdown.$search || container.selection.$search || + $container.find('.select2-search__field'); + }; + + Tokenizer.prototype.query = function (decorated, params, callback) { + var self = this; + + function createAndSelect (data) { + // Normalize the data object so we can use it for checks + var item = self._normalizeItem(data); + + // Check if the data object already exists as a tag + // Select it if it doesn't + var $existingOptions = self.$element.find('option').filter(function () { + return $(this).val() === item.id; + }); + + // If an existing option wasn't found for it, create the option + if (!$existingOptions.length) { + var $option = self.option(item); + $option.attr('data-select2-tag', true); + + self._removeOldTags(); + self.addOptions([$option]); + } + + // Select the item, now that we know there is an option for it + select(item); + } + + function select (data) { + self.trigger('select', { + data: data + }); + } + + params.term = params.term || ''; + + var tokenData = this.tokenizer(params, this.options, createAndSelect); + + if (tokenData.term !== params.term) { + // Replace the search term if we have the search box + if (this.$search.length) { + this.$search.val(tokenData.term); + this.$search.focus(); + } + + params.term = tokenData.term; + } + + decorated.call(this, params, callback); + }; + + Tokenizer.prototype.tokenizer = function (_, params, options, callback) { + var separators = options.get('tokenSeparators') || []; + var term = params.term; + var i = 0; + + var createTag = this.createTag || function (params) { + return { + id: params.term, + text: params.term + }; + }; + + while (i < term.length) { + var termChar = term[i]; + + if ($.inArray(termChar, separators) === -1) { + i++; + + continue; + } + + var part = term.substr(0, i); + var partParams = $.extend({}, params, { + term: part + }); + + var data = createTag(partParams); + + if (data == null) { + i++; + continue; + } + + callback(data); + + // Reset the term to not include the tokenized portion + term = term.substr(i + 1) || ''; + i = 0; + } + + return { + term: term + }; + }; + + return Tokenizer; +}); + +S2.define('select2/data/minimumInputLength',[ + +], function () { + function MinimumInputLength (decorated, $e, options) { + this.minimumInputLength = options.get('minimumInputLength'); + + decorated.call(this, $e, options); + } + + MinimumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (params.term.length < this.minimumInputLength) { + this.trigger('results:message', { + message: 'inputTooShort', + args: { + minimum: this.minimumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MinimumInputLength; +}); + +S2.define('select2/data/maximumInputLength',[ + +], function () { + function MaximumInputLength (decorated, $e, options) { + this.maximumInputLength = options.get('maximumInputLength'); + + decorated.call(this, $e, options); + } + + MaximumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (this.maximumInputLength > 0 && + params.term.length > this.maximumInputLength) { + this.trigger('results:message', { + message: 'inputTooLong', + args: { + maximum: this.maximumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MaximumInputLength; +}); + +S2.define('select2/data/maximumSelectionLength',[ + +], function (){ + function MaximumSelectionLength (decorated, $e, options) { + this.maximumSelectionLength = options.get('maximumSelectionLength'); + + decorated.call(this, $e, options); + } + + MaximumSelectionLength.prototype.query = + function (decorated, params, callback) { + var self = this; + + this.current(function (currentData) { + var count = currentData != null ? currentData.length : 0; + if (self.maximumSelectionLength > 0 && + count >= self.maximumSelectionLength) { + self.trigger('results:message', { + message: 'maximumSelected', + args: { + maximum: self.maximumSelectionLength + } + }); + return; + } + decorated.call(self, params, callback); + }); + }; + + return MaximumSelectionLength; +}); + +S2.define('select2/dropdown',[ + 'jquery', + './utils' +], function ($, Utils) { + function Dropdown ($element, options) { + this.$element = $element; + this.options = options; + + Dropdown.__super__.constructor.call(this); + } + + Utils.Extend(Dropdown, Utils.Observable); + + Dropdown.prototype.render = function () { + var $dropdown = $( + '' + + '' + + '' + ); + + $dropdown.attr('dir', this.options.get('dir')); + + this.$dropdown = $dropdown; + + return $dropdown; + }; + + Dropdown.prototype.bind = function () { + // Should be implemented in subclasses + }; + + Dropdown.prototype.position = function ($dropdown, $container) { + // Should be implmented in subclasses + }; + + Dropdown.prototype.destroy = function () { + // Remove the dropdown from the DOM + this.$dropdown.remove(); + }; + + return Dropdown; +}); + +S2.define('select2/dropdown/search',[ + 'jquery', + '../utils' +], function ($, Utils) { + function Search () { } + + Search.prototype.render = function (decorated) { + var $rendered = decorated.call(this); + + var $search = $( + '' + + '' + + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + $rendered.prepend($search); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + this.$search.on('keydown', function (evt) { + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + }); + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$search.on('input', function (evt) { + // Unbind the duplicated `keyup` event + $(this).off('keyup'); + }); + + this.$search.on('keyup input', function (evt) { + self.handleSearch(evt); + }); + + container.on('open', function () { + self.$search.attr('tabindex', 0); + + self.$search.focus(); + + window.setTimeout(function () { + self.$search.focus(); + }, 0); + }); + + container.on('close', function () { + self.$search.attr('tabindex', -1); + + self.$search.val(''); + }); + + container.on('focus', function () { + if (container.isOpen()) { + self.$search.focus(); + } + }); + + container.on('results:all', function (params) { + if (params.query.term == null || params.query.term === '') { + var showSearch = self.showSearch(params); + + if (showSearch) { + self.$searchContainer.removeClass('select2-search--hide'); + } else { + self.$searchContainer.addClass('select2-search--hide'); + } + } + }); + }; + + Search.prototype.handleSearch = function (evt) { + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.showSearch = function (_, params) { + return true; + }; + + return Search; +}); + +S2.define('select2/dropdown/hidePlaceholder',[ + +], function () { + function HidePlaceholder (decorated, $element, options, dataAdapter) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options, dataAdapter); + } + + HidePlaceholder.prototype.append = function (decorated, data) { + data.results = this.removePlaceholder(data.results); + + decorated.call(this, data); + }; + + HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + HidePlaceholder.prototype.removePlaceholder = function (_, data) { + var modifiedData = data.slice(0); + + for (var d = data.length - 1; d >= 0; d--) { + var item = data[d]; + + if (this.placeholder.id === item.id) { + modifiedData.splice(d, 1); + } + } + + return modifiedData; + }; + + return HidePlaceholder; +}); + +S2.define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + this.loading = false; + + decorated.call(this, data); + + if (this.showLoadingMore(data)) { + this.$results.append(this.$loadingMore); + } + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + self.$loadingMore[0] + ); + + if (self.loading || !isLoadMoreVisible) { + return; + } + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var loadingMoreOffset = self.$loadingMore.offset().top + + self.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + self.loadMore(); + } + }); + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.showLoadingMore = function (_, data) { + return data.pagination && data.pagination.more; + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
      • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + +S2.define('select2/dropdown/attachBody',[ + 'jquery', + '../utils' +], function ($, Utils) { + function AttachBody (decorated, $element, options) { + this.$dropdownParent = options.get('dropdownParent') || $(document.body); + + decorated.call(this, $element, options); + } + + AttachBody.prototype.bind = function (decorated, container, $container) { + var self = this; + + var setupResultsEvents = false; + + decorated.call(this, container, $container); + + container.on('open', function () { + self._showDropdown(); + self._attachPositioningHandler(container); + + if (!setupResultsEvents) { + setupResultsEvents = true; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + } + }); + + container.on('close', function () { + self._hideDropdown(); + self._detachPositioningHandler(container); + }); + + this.$dropdownContainer.on('mousedown', function (evt) { + evt.stopPropagation(); + }); + }; + + AttachBody.prototype.destroy = function (decorated) { + decorated.call(this); + + this.$dropdownContainer.remove(); + }; + + AttachBody.prototype.position = function (decorated, $dropdown, $container) { + // Clone all of the container classes + $dropdown.attr('class', $container.attr('class')); + + $dropdown.removeClass('select2'); + $dropdown.addClass('select2-container--open'); + + $dropdown.css({ + position: 'absolute', + top: -999999 + }); + + this.$container = $container; + }; + + AttachBody.prototype.render = function (decorated) { + var $container = $(''); + + var $dropdown = decorated.call(this); + $container.append($dropdown); + + this.$dropdownContainer = $container; + + return $container; + }; + + AttachBody.prototype._hideDropdown = function (decorated) { + this.$dropdownContainer.detach(); + }; + + AttachBody.prototype._attachPositioningHandler = + function (decorated, container) { + var self = this; + + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.each(function () { + $(this).data('select2-scroll-position', { + x: $(this).scrollLeft(), + y: $(this).scrollTop() + }); + }); + + $watchers.on(scrollEvent, function (ev) { + var position = $(this).data('select2-scroll-position'); + $(this).scrollTop(position.y); + }); + + $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, + function (e) { + self._positionDropdown(); + self._resizeDropdown(); + }); + }; + + AttachBody.prototype._detachPositioningHandler = + function (decorated, container) { + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.off(scrollEvent); + + $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent); + }; + + AttachBody.prototype._positionDropdown = function () { + var $window = $(window); + + var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above'); + var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below'); + + var newDirection = null; + + var offset = this.$container.offset(); + + offset.bottom = offset.top + this.$container.outerHeight(false); + + var container = { + height: this.$container.outerHeight(false) + }; + + container.top = offset.top; + container.bottom = offset.top + container.height; + + var dropdown = { + height: this.$dropdown.outerHeight(false) + }; + + var viewport = { + top: $window.scrollTop(), + bottom: $window.scrollTop() + $window.height() + }; + + var enoughRoomAbove = viewport.top < (offset.top - dropdown.height); + var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height); + + var css = { + left: offset.left, + top: container.bottom + }; + + // Determine what the parent element is to use for calciulating the offset + var $offsetParent = this.$dropdownParent; + + // For statically positoned elements, we need to get the element + // that is determining the offset + if ($offsetParent.css('position') === 'static') { + $offsetParent = $offsetParent.offsetParent(); + } + + var parentOffset = $offsetParent.offset(); + + css.top -= parentOffset.top; + css.left -= parentOffset.left; + + if (!isCurrentlyAbove && !isCurrentlyBelow) { + newDirection = 'below'; + } + + if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) { + newDirection = 'above'; + } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) { + newDirection = 'below'; + } + + if (newDirection == 'above' || + (isCurrentlyAbove && newDirection !== 'below')) { + css.top = container.top - parentOffset.top - dropdown.height; + } + + if (newDirection != null) { + this.$dropdown + .removeClass('select2-dropdown--below select2-dropdown--above') + .addClass('select2-dropdown--' + newDirection); + this.$container + .removeClass('select2-container--below select2-container--above') + .addClass('select2-container--' + newDirection); + } + + this.$dropdownContainer.css(css); + }; + + AttachBody.prototype._resizeDropdown = function () { + var css = { + width: this.$container.outerWidth(false) + 'px' + }; + + if (this.options.get('dropdownAutoWidth')) { + css.minWidth = css.width; + css.position = 'relative'; + css.width = 'auto'; + } + + this.$dropdown.css(css); + }; + + AttachBody.prototype._showDropdown = function (decorated) { + this.$dropdownContainer.appendTo(this.$dropdownParent); + + this._positionDropdown(); + this._resizeDropdown(); + }; + + return AttachBody; +}); + +S2.define('select2/dropdown/minimumResultsForSearch',[ + +], function () { + function countResults (data) { + var count = 0; + + for (var d = 0; d < data.length; d++) { + var item = data[d]; + + if (item.children) { + count += countResults(item.children); + } else { + count++; + } + } + + return count; + } + + function MinimumResultsForSearch (decorated, $element, options, dataAdapter) { + this.minimumResultsForSearch = options.get('minimumResultsForSearch'); + + if (this.minimumResultsForSearch < 0) { + this.minimumResultsForSearch = Infinity; + } + + decorated.call(this, $element, options, dataAdapter); + } + + MinimumResultsForSearch.prototype.showSearch = function (decorated, params) { + if (countResults(params.data.results) < this.minimumResultsForSearch) { + return false; + } + + return decorated.call(this, params); + }; + + return MinimumResultsForSearch; +}); + +S2.define('select2/dropdown/selectOnClose',[ + +], function () { + function SelectOnClose () { } + + SelectOnClose.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('close', function (params) { + self._handleSelectOnClose(params); + }); + }; + + SelectOnClose.prototype._handleSelectOnClose = function (_, params) { + if (params && params.originalSelect2Event != null) { + var event = params.originalSelect2Event; + + // Don't select an item if the close event was triggered from a select or + // unselect event + if (event._type === 'select' || event._type === 'unselect') { + return; + } + } + + var $highlightedResults = this.getHighlightedResults(); + + // Only select highlighted results + if ($highlightedResults.length < 1) { + return; + } + + var data = $highlightedResults.data('data'); + + // Don't re-select already selected resulte + if ( + (data.element != null && data.element.selected) || + (data.element == null && data.selected) + ) { + return; + } + + this.trigger('select', { + data: data + }); + }; + + return SelectOnClose; +}); + +S2.define('select2/dropdown/closeOnSelect',[ + +], function () { + function CloseOnSelect () { } + + CloseOnSelect.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function (evt) { + self._selectTriggered(evt); + }); + + container.on('unselect', function (evt) { + self._selectTriggered(evt); + }); + }; + + CloseOnSelect.prototype._selectTriggered = function (_, evt) { + var originalEvent = evt.originalEvent; + + // Don't close if the control key is being held + if (originalEvent && originalEvent.ctrlKey) { + return; + } + + this.trigger('close', { + originalEvent: originalEvent, + originalSelect2Event: evt + }); + }; + + return CloseOnSelect; +}); + +S2.define('select2/i18n/en',[],function () { + // English + return { + errorLoading: function () { + return 'The results could not be loaded.'; + }, + inputTooLong: function (args) { + var overChars = args.input.length - args.maximum; + + var message = 'Please delete ' + overChars + ' character'; + + if (overChars != 1) { + message += 's'; + } + + return message; + }, + inputTooShort: function (args) { + var remainingChars = args.minimum - args.input.length; + + var message = 'Please enter ' + remainingChars + ' or more characters'; + + return message; + }, + loadingMore: function () { + return 'Loading more results…'; + }, + maximumSelected: function (args) { + var message = 'You can only select ' + args.maximum + ' item'; + + if (args.maximum != 1) { + message += 's'; + } + + return message; + }, + noResults: function () { + return 'No results found'; + }, + searching: function () { + return 'Searching…'; + } + }; +}); + +S2.define('select2/defaults',[ + 'jquery', + 'require', + + './results', + + './selection/single', + './selection/multiple', + './selection/placeholder', + './selection/allowClear', + './selection/search', + './selection/eventRelay', + + './utils', + './translation', + './diacritics', + + './data/select', + './data/array', + './data/ajax', + './data/tags', + './data/tokenizer', + './data/minimumInputLength', + './data/maximumInputLength', + './data/maximumSelectionLength', + + './dropdown', + './dropdown/search', + './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', + './dropdown/attachBody', + './dropdown/minimumResultsForSearch', + './dropdown/selectOnClose', + './dropdown/closeOnSelect', + + './i18n/en' +], function ($, require, + + ResultsList, + + SingleSelection, MultipleSelection, Placeholder, AllowClear, + SelectionSearch, EventRelay, + + Utils, Translation, DIACRITICS, + + SelectData, ArrayData, AjaxData, Tags, Tokenizer, + MinimumInputLength, MaximumInputLength, MaximumSelectionLength, + + Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, + AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, + + EnglishTranslation) { + function Defaults () { + this.reset(); + } + + Defaults.prototype.apply = function (options) { + options = $.extend(true, {}, this.defaults, options); + + if (options.dataAdapter == null) { + if (options.ajax != null) { + options.dataAdapter = AjaxData; + } else if (options.data != null) { + options.dataAdapter = ArrayData; + } else { + options.dataAdapter = SelectData; + } + + if (options.minimumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MinimumInputLength + ); + } + + if (options.maximumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumInputLength + ); + } + + if (options.maximumSelectionLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumSelectionLength + ); + } + + if (options.tags) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + + if (options.tokenSeparators != null || options.tokenizer != null) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Tokenizer + ); + } + + if (options.query != null) { + var Query = require(options.amdBase + 'compat/query'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Query + ); + } + + if (options.initSelection != null) { + var InitSelection = require(options.amdBase + 'compat/initSelection'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + InitSelection + ); + } + } + + if (options.resultsAdapter == null) { + options.resultsAdapter = ResultsList; + + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + + if (options.placeholder != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + HidePlaceholder + ); + } + + if (options.selectOnClose) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + SelectOnClose + ); + } + } + + if (options.dropdownAdapter == null) { + if (options.multiple) { + options.dropdownAdapter = Dropdown; + } else { + var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch); + + options.dropdownAdapter = SearchableDropdown; + } + + if (options.minimumResultsForSearch !== 0) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + MinimumResultsForSearch + ); + } + + if (options.closeOnSelect) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + CloseOnSelect + ); + } + + if ( + options.dropdownCssClass != null || + options.dropdownCss != null || + options.adaptDropdownCssClass != null + ) { + var DropdownCSS = require(options.amdBase + 'compat/dropdownCss'); + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + DropdownCSS + ); + } + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + AttachBody + ); + } + + if (options.selectionAdapter == null) { + if (options.multiple) { + options.selectionAdapter = MultipleSelection; + } else { + options.selectionAdapter = SingleSelection; + } + + // Add the placeholder mixin if a placeholder was specified + if (options.placeholder != null) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + Placeholder + ); + } + + if (options.allowClear) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + AllowClear + ); + } + + if (options.multiple) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + SelectionSearch + ); + } + + if ( + options.containerCssClass != null || + options.containerCss != null || + options.adaptContainerCssClass != null + ) { + var ContainerCSS = require(options.amdBase + 'compat/containerCss'); + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + ContainerCSS + ); + } + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + EventRelay + ); + } + + if (typeof options.language === 'string') { + // Check if the language is specified with a region + if (options.language.indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = options.language.split('-'); + var baseLanguage = languageParts[0]; + + options.language = [options.language, baseLanguage]; + } else { + options.language = [options.language]; + } + } + + if ($.isArray(options.language)) { + var languages = new Translation(); + options.language.push('en'); + + var languageNames = options.language; + + for (var l = 0; l < languageNames.length; l++) { + var name = languageNames[l]; + var language = {}; + + try { + // Try to load it with the original name + language = Translation.loadPath(name); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + name = this.defaults.amdLanguageBase + name; + language = Translation.loadPath(name); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files. + if (options.debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + name + '" could not be ' + + 'automatically loaded. A fallback will be used instead.' + ); + } + + continue; + } + } + + languages.extend(language); + } + + options.translations = languages; + } else { + var baseTranslation = Translation.loadPath( + this.defaults.amdLanguageBase + 'en' + ); + var customTranslation = new Translation(options.language); + + customTranslation.extend(baseTranslation); + + options.translations = customTranslation; + } + + return options; + }; + + Defaults.prototype.reset = function () { + function stripDiacritics (text) { + // Used 'uni range + named function' from http://jsperf.com/diacritics/18 + function match(a) { + return DIACRITICS[a] || a; + } + + return text.replace(/[^\u0000-\u007E]/g, match); + } + + function matcher (params, data) { + // Always return the object if there is nothing to compare + if ($.trim(params.term) === '') { + return data; + } + + // Do a recursive check for options with children + if (data.children && data.children.length > 0) { + // Clone the data object if there are children + // This is required as we modify the object to remove any non-matches + var match = $.extend(true, {}, data); + + // Check each child of the option + for (var c = data.children.length - 1; c >= 0; c--) { + var child = data.children[c]; + + var matches = matcher(params, child); + + // If there wasn't a match, remove the object in the array + if (matches == null) { + match.children.splice(c, 1); + } + } + + // If any children matched, return the new object + if (match.children.length > 0) { + return match; + } + + // If there were no matching children, check just the plain object + return matcher(params, match); + } + + var original = stripDiacritics(data.text).toUpperCase(); + var term = stripDiacritics(params.term).toUpperCase(); + + // Check if the text contains the term + if (original.indexOf(term) > -1) { + return data; + } + + // If it doesn't contain the term, don't return anything + return null; + } + + this.defaults = { + amdBase: './', + amdLanguageBase: './i18n/', + closeOnSelect: true, + debug: false, + dropdownAutoWidth: false, + escapeMarkup: Utils.escapeMarkup, + language: EnglishTranslation, + matcher: matcher, + minimumInputLength: 0, + maximumInputLength: 0, + maximumSelectionLength: 0, + minimumResultsForSearch: 0, + selectOnClose: false, + sorter: function (data) { + return data; + }, + templateResult: function (result) { + return result.text; + }, + templateSelection: function (selection) { + return selection.text; + }, + theme: 'default', + width: 'resolve' + }; + }; + + Defaults.prototype.set = function (key, value) { + var camelKey = $.camelCase(key); + + var data = {}; + data[camelKey] = value; + + var convertedData = Utils._convertData(data); + + $.extend(this.defaults, convertedData); + }; + + var defaults = new Defaults(); + + return defaults; +}); + +S2.define('select2/options',[ + 'require', + 'jquery', + './defaults', + './utils' +], function (require, $, Defaults, Utils) { + function Options (options, $element) { + this.options = options; + + if ($element != null) { + this.fromElement($element); + } + + this.options = Defaults.apply(this.options); + + if ($element && $element.is('input')) { + var InputCompat = require(this.get('amdBase') + 'compat/inputData'); + + this.options.dataAdapter = Utils.Decorate( + this.options.dataAdapter, + InputCompat + ); + } + } + + Options.prototype.fromElement = function ($e) { + var excludedData = ['select2']; + + if (this.options.multiple == null) { + this.options.multiple = $e.prop('multiple'); + } + + if (this.options.disabled == null) { + this.options.disabled = $e.prop('disabled'); + } + + if (this.options.language == null) { + if ($e.prop('lang')) { + this.options.language = $e.prop('lang').toLowerCase(); + } else if ($e.closest('[lang]').prop('lang')) { + this.options.language = $e.closest('[lang]').prop('lang'); + } + } + + if (this.options.dir == null) { + if ($e.prop('dir')) { + this.options.dir = $e.prop('dir'); + } else if ($e.closest('[dir]').prop('dir')) { + this.options.dir = $e.closest('[dir]').prop('dir'); + } else { + this.options.dir = 'ltr'; + } + } + + $e.prop('disabled', this.options.disabled); + $e.prop('multiple', this.options.multiple); + + if ($e.data('select2Tags')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-select2-tags` attribute has been changed to ' + + 'use the `data-data` and `data-tags="true"` attributes and will be ' + + 'removed in future versions of Select2.' + ); + } + + $e.data('data', $e.data('select2Tags')); + $e.data('tags', true); + } + + if ($e.data('ajaxUrl')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-ajax-url` attribute has been changed to ' + + '`data-ajax--url` and support for the old attribute will be removed' + + ' in future versions of Select2.' + ); + } + + $e.attr('ajax--url', $e.data('ajaxUrl')); + $e.data('ajax--url', $e.data('ajaxUrl')); + } + + var dataset = {}; + + // Prefer the element's `dataset` attribute if it exists + // jQuery 1.x does not correctly handle data attributes with multiple dashes + if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { + dataset = $.extend(true, {}, $e[0].dataset, $e.data()); + } else { + dataset = $e.data(); + } + + var data = $.extend(true, {}, dataset); + + data = Utils._convertData(data); + + for (var key in data) { + if ($.inArray(key, excludedData) > -1) { + continue; + } + + if ($.isPlainObject(this.options[key])) { + $.extend(this.options[key], data[key]); + } else { + this.options[key] = data[key]; + } + } + + return this; + }; + + Options.prototype.get = function (key) { + return this.options[key]; + }; + + Options.prototype.set = function (key, val) { + this.options[key] = val; + }; + + return Options; +}); + +S2.define('select2/core',[ + 'jquery', + './options', + './utils', + './keys' +], function ($, Options, Utils, KEYS) { + var Select2 = function ($element, options) { + if ($element.data('select2') != null) { + $element.data('select2').destroy(); + } + + this.$element = $element; + + this.id = this._generateId($element); + + options = options || {}; + + this.options = new Options(options, $element); + + Select2.__super__.constructor.call(this); + + // Set up the tabindex + + var tabindex = $element.attr('tabindex') || 0; + $element.data('old-tabindex', tabindex); + $element.attr('tabindex', '-1'); + + // Set up containers and adapters + + var DataAdapter = this.options.get('dataAdapter'); + this.dataAdapter = new DataAdapter($element, this.options); + + var $container = this.render(); + + this._placeContainer($container); + + var SelectionAdapter = this.options.get('selectionAdapter'); + this.selection = new SelectionAdapter($element, this.options); + this.$selection = this.selection.render(); + + this.selection.position(this.$selection, $container); + + var DropdownAdapter = this.options.get('dropdownAdapter'); + this.dropdown = new DropdownAdapter($element, this.options); + this.$dropdown = this.dropdown.render(); + + this.dropdown.position(this.$dropdown, $container); + + var ResultsAdapter = this.options.get('resultsAdapter'); + this.results = new ResultsAdapter($element, this.options, this.dataAdapter); + this.$results = this.results.render(); + + this.results.position(this.$results, this.$dropdown); + + // Bind events + + var self = this; + + // Bind the container to all of the adapters + this._bindAdapters(); + + // Register any DOM event handlers + this._registerDomEvents(); + + // Register any internal event handlers + this._registerDataEvents(); + this._registerSelectionEvents(); + this._registerDropdownEvents(); + this._registerResultsEvents(); + this._registerEvents(); + + // Set the initial state + this.dataAdapter.current(function (initialData) { + self.trigger('selection:update', { + data: initialData + }); + }); + + // Hide the original select + $element.addClass('select2-hidden-accessible'); + $element.attr('aria-hidden', 'true'); + + // Synchronize any monitored attributes + this._syncAttributes(); + + $element.data('select2', this); + }; + + Utils.Extend(Select2, Utils.Observable); + + Select2.prototype._generateId = function ($element) { + var id = ''; + + if ($element.attr('id') != null) { + id = $element.attr('id'); + } else if ($element.attr('name') != null) { + id = $element.attr('name') + '-' + Utils.generateChars(2); + } else { + id = Utils.generateChars(4); + } + + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = 'select2-' + id; + + return id; + }; + + Select2.prototype._placeContainer = function ($container) { + $container.insertAfter(this.$element); + + var width = this._resolveWidth(this.$element, this.options.get('width')); + + if (width != null) { + $container.css('width', width); + } + }; + + Select2.prototype._resolveWidth = function ($element, method) { + var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i; + + if (method == 'resolve') { + var styleWidth = this._resolveWidth($element, 'style'); + + if (styleWidth != null) { + return styleWidth; + } + + return this._resolveWidth($element, 'element'); + } + + if (method == 'element') { + var elementWidth = $element.outerWidth(false); + + if (elementWidth <= 0) { + return 'auto'; + } + + return elementWidth + 'px'; + } + + if (method == 'style') { + var style = $element.attr('style'); + + if (typeof(style) !== 'string') { + return null; + } + + var attrs = style.split(';'); + + for (var i = 0, l = attrs.length; i < l; i = i + 1) { + var attr = attrs[i].replace(/\s/g, ''); + var matches = attr.match(WIDTH); + + if (matches !== null && matches.length >= 1) { + return matches[1]; + } + } + + return null; + } + + return method; + }; + + Select2.prototype._bindAdapters = function () { + this.dataAdapter.bind(this, this.$container); + this.selection.bind(this, this.$container); + + this.dropdown.bind(this, this.$container); + this.results.bind(this, this.$container); + }; + + Select2.prototype._registerDomEvents = function () { + var self = this; + + this.$element.on('change.select2', function () { + self.dataAdapter.current(function (data) { + self.trigger('selection:update', { + data: data + }); + }); + }); + + this.$element.on('focus.select2', function (evt) { + self.trigger('focus', evt); + }); + + this._syncA = Utils.bind(this._syncAttributes, this); + this._syncS = Utils.bind(this._syncSubtree, this); + + if (this.$element[0].attachEvent) { + this.$element[0].attachEvent('onpropertychange', this._syncA); + } + + var observer = window.MutationObserver || + window.WebKitMutationObserver || + window.MozMutationObserver + ; + + if (observer != null) { + this._observer = new observer(function (mutations) { + $.each(mutations, self._syncA); + $.each(mutations, self._syncS); + }); + this._observer.observe(this.$element[0], { + attributes: true, + childList: true, + subtree: false + }); + } else if (this.$element[0].addEventListener) { + this.$element[0].addEventListener( + 'DOMAttrModified', + self._syncA, + false + ); + this.$element[0].addEventListener( + 'DOMNodeInserted', + self._syncS, + false + ); + this.$element[0].addEventListener( + 'DOMNodeRemoved', + self._syncS, + false + ); + } + }; + + Select2.prototype._registerDataEvents = function () { + var self = this; + + this.dataAdapter.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerSelectionEvents = function () { + var self = this; + var nonRelayEvents = ['toggle', 'focus']; + + this.selection.on('toggle', function () { + self.toggleDropdown(); + }); + + this.selection.on('focus', function (params) { + self.focus(params); + }); + + this.selection.on('*', function (name, params) { + if ($.inArray(name, nonRelayEvents) !== -1) { + return; + } + + self.trigger(name, params); + }); + }; + + Select2.prototype._registerDropdownEvents = function () { + var self = this; + + this.dropdown.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerResultsEvents = function () { + var self = this; + + this.results.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerEvents = function () { + var self = this; + + this.on('open', function () { + self.$container.addClass('select2-container--open'); + }); + + this.on('close', function () { + self.$container.removeClass('select2-container--open'); + }); + + this.on('enable', function () { + self.$container.removeClass('select2-container--disabled'); + }); + + this.on('disable', function () { + self.$container.addClass('select2-container--disabled'); + }); + + this.on('blur', function () { + self.$container.removeClass('select2-container--focus'); + }); + + this.on('query', function (params) { + if (!self.isOpen()) { + self.trigger('open', {}); + } + + this.dataAdapter.query(params, function (data) { + self.trigger('results:all', { + data: data, + query: params + }); + }); + }); + + this.on('query:append', function (params) { + this.dataAdapter.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + + this.on('keypress', function (evt) { + var key = evt.which; + + if (self.isOpen()) { + if (key === KEYS.ESC || key === KEYS.TAB || + (key === KEYS.UP && evt.altKey)) { + self.close(); + + evt.preventDefault(); + } else if (key === KEYS.ENTER) { + self.trigger('results:select', {}); + + evt.preventDefault(); + } else if ((key === KEYS.SPACE && evt.ctrlKey)) { + self.trigger('results:toggle', {}); + + evt.preventDefault(); + } else if (key === KEYS.UP) { + self.trigger('results:previous', {}); + + evt.preventDefault(); + } else if (key === KEYS.DOWN) { + self.trigger('results:next', {}); + + evt.preventDefault(); + } + } else { + if (key === KEYS.ENTER || key === KEYS.SPACE || + (key === KEYS.DOWN && evt.altKey)) { + self.open(); + + evt.preventDefault(); + } + } + }); + }; + + Select2.prototype._syncAttributes = function () { + this.options.set('disabled', this.$element.prop('disabled')); + + if (this.options.get('disabled')) { + if (this.isOpen()) { + this.close(); + } + + this.trigger('disable', {}); + } else { + this.trigger('enable', {}); + } + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = false; + var self = this; + + // Ignore any mutation events raised for elements that aren't options or + // optgroups. This handles the case when the select element is destroyed + if ( + evt && evt.target && ( + evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP' + ) + ) { + return; + } + + if (!mutations) { + // If mutation events aren't supported, then we can only assume that the + // change affected the selections + changed = true; + } else if (mutations.addedNodes && mutations.addedNodes.length > 0) { + for (var n = 0; n < mutations.addedNodes.length; n++) { + var node = mutations.addedNodes[n]; + + if (node.selected) { + changed = true; + } + } + } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { + changed = true; + } + + // Only re-pull the data if we think there is a change + if (changed) { + this.dataAdapter.current(function (currentData) { + self.trigger('selection:update', { + data: currentData + }); + }); + } + }; + + /** + * Override the trigger method to automatically trigger pre-events when + * there are events that can be prevented. + */ + Select2.prototype.trigger = function (name, args) { + var actualTrigger = Select2.__super__.trigger; + var preTriggerMap = { + 'open': 'opening', + 'close': 'closing', + 'select': 'selecting', + 'unselect': 'unselecting' + }; + + if (args === undefined) { + args = {}; + } + + if (name in preTriggerMap) { + var preTriggerName = preTriggerMap[name]; + var preTriggerArgs = { + prevented: false, + name: name, + args: args + }; + + actualTrigger.call(this, preTriggerName, preTriggerArgs); + + if (preTriggerArgs.prevented) { + args.prevented = true; + + return; + } + } + + actualTrigger.call(this, name, args); + }; + + Select2.prototype.toggleDropdown = function () { + if (this.options.get('disabled')) { + return; + } + + if (this.isOpen()) { + this.close(); + } else { + this.open(); + } + }; + + Select2.prototype.open = function () { + if (this.isOpen()) { + return; + } + + this.trigger('query', {}); + }; + + Select2.prototype.close = function () { + if (!this.isOpen()) { + return; + } + + this.trigger('close', {}); + }; + + Select2.prototype.isOpen = function () { + return this.$container.hasClass('select2-container--open'); + }; + + Select2.prototype.hasFocus = function () { + return this.$container.hasClass('select2-container--focus'); + }; + + Select2.prototype.focus = function (data) { + // No need to re-trigger focus events if we are already focused + if (this.hasFocus()) { + return; + } + + this.$container.addClass('select2-container--focus'); + this.trigger('focus', {}); + }; + + Select2.prototype.enable = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("enable")` method has been deprecated and will' + + ' be removed in later Select2 versions. Use $element.prop("disabled")' + + ' instead.' + ); + } + + if (args == null || args.length === 0) { + args = [true]; + } + + var disabled = !args[0]; + + this.$element.prop('disabled', disabled); + }; + + Select2.prototype.data = function () { + if (this.options.get('debug') && + arguments.length > 0 && window.console && console.warn) { + console.warn( + 'Select2: Data can no longer be set using `select2("data")`. You ' + + 'should consider setting the value instead using `$element.val()`.' + ); + } + + var data = []; + + this.dataAdapter.current(function (currentData) { + data = currentData; + }); + + return data; + }; + + Select2.prototype.val = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("val")` method has been deprecated and will be' + + ' removed in later Select2 versions. Use $element.val() instead.' + ); + } + + if (args == null || args.length === 0) { + return this.$element.val(); + } + + var newVal = args[0]; + + if ($.isArray(newVal)) { + newVal = $.map(newVal, function (obj) { + return obj.toString(); + }); + } + + this.$element.val(newVal).trigger('change'); + }; + + Select2.prototype.destroy = function () { + this.$container.remove(); + + if (this.$element[0].detachEvent) { + this.$element[0].detachEvent('onpropertychange', this._syncA); + } + + if (this._observer != null) { + this._observer.disconnect(); + this._observer = null; + } else if (this.$element[0].removeEventListener) { + this.$element[0] + .removeEventListener('DOMAttrModified', this._syncA, false); + this.$element[0] + .removeEventListener('DOMNodeInserted', this._syncS, false); + this.$element[0] + .removeEventListener('DOMNodeRemoved', this._syncS, false); + } + + this._syncA = null; + this._syncS = null; + + this.$element.off('.select2'); + this.$element.attr('tabindex', this.$element.data('old-tabindex')); + + this.$element.removeClass('select2-hidden-accessible'); + this.$element.attr('aria-hidden', 'false'); + this.$element.removeData('select2'); + + this.dataAdapter.destroy(); + this.selection.destroy(); + this.dropdown.destroy(); + this.results.destroy(); + + this.dataAdapter = null; + this.selection = null; + this.dropdown = null; + this.results = null; + }; + + Select2.prototype.render = function () { + var $container = $( + '' + + '' + + '' + + '' + ); + + $container.attr('dir', this.options.get('dir')); + + this.$container = $container; + + this.$container.addClass('select2-container--' + this.options.get('theme')); + + $container.data('element', this.$element); + + return $container; + }; + + return Select2; +}); + +S2.define('jquery-mousewheel',[ + 'jquery' +], function ($) { + // Used to shim jQuery.mousewheel for non-full builds. + return $; +}); + +S2.define('jquery.select2',[ + 'jquery', + 'jquery-mousewheel', + + './select2/core', + './select2/defaults' +], function ($, _, Select2, Defaults) { + if ($.fn.select2 == null) { + // All methods that should return the element + var thisMethods = ['open', 'close', 'destroy']; + + $.fn.select2 = function (options) { + options = options || {}; + + if (typeof options === 'object') { + this.each(function () { + var instanceOptions = $.extend(true, {}, options); + + var instance = new Select2($(this), instanceOptions); + }); + + return this; + } else if (typeof options === 'string') { + var ret; + var args = Array.prototype.slice.call(arguments, 1); + + this.each(function () { + var instance = $(this).data('select2'); + + if (instance == null && window.console && console.error) { + console.error( + 'The select2(\'' + options + '\') method was called on an ' + + 'element that is not using Select2.' + ); + } + + ret = instance[options].apply(instance, args); + }); + + // Check if we should be returning `this` + if ($.inArray(options, thisMethods) > -1) { + return this; + } + + return ret; + } else { + throw new Error('Invalid arguments for Select2: ' + options); + } + }; + } + + if ($.fn.select2.defaults == null) { + $.fn.select2.defaults = Defaults; + } + + return Select2; +}); + + // Return the AMD loader configuration so it can be used outside of this file + return { + define: S2.define, + require: S2.require + }; +}()); + + // Autoload the jQuery bindings + // We know that all of the modules exist above this, so we're safe + var select2 = S2.require('jquery.select2'); + + // Hold the AMD module references on the jQuery function that was just loaded + // This allows Select2 to use the internal loader outside of this file, such + // as in the language files. + jQuery.fn.select2.amd = S2; + + // Return the Select2 instance for anyone who is importing it. + return select2; +})); diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-assets.php b/plugins/woocommerce/includes/admin/class-wc-admin-assets.php index cf191c483e2..f93b755c6c1 100644 --- a/plugins/woocommerce/includes/admin/class-wc-admin-assets.php +++ b/plugins/woocommerce/includes/admin/class-wc-admin-assets.php @@ -149,7 +149,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) : wp_register_script( 'wc-shipping-zone-methods', WC()->plugin_url() . '/assets/js/admin/wc-shipping-zone-methods' . $suffix . '.js', array( 'jquery', 'wp-util', 'underscore', 'backbone', 'jquery-ui-sortable', 'wc-backbone-modal' ), $version ); wp_register_script( 'wc-shipping-classes', WC()->plugin_url() . '/assets/js/admin/wc-shipping-classes' . $suffix . '.js', array( 'jquery', 'wp-util', 'underscore', 'backbone', 'wc-backbone-modal' ), $version, array( 'in_footer' => false ) ); wp_register_script( 'wc-clipboard', WC()->plugin_url() . '/assets/js/admin/wc-clipboard' . $suffix . '.js', array( 'jquery' ), $version ); - wp_register_script( 'select2', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full' . $suffix . '.js', array( 'jquery' ), '1.0.6' ); + wp_register_script( 'select2', WC()->plugin_url() . '/assets/js/select2/select2.full' . $suffix . '.js', array( 'jquery' ), '4.0.3', array( 'in_footer' => false ) ); wp_register_script( 'selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full' . $suffix . '.js', array( 'jquery' ), '1.0.6' ); wp_register_script( 'wc-enhanced-select', WC()->plugin_url() . '/assets/js/admin/wc-enhanced-select' . $suffix . '.js', array( 'jquery', 'selectWoo' ), $version ); wp_register_script( 'js-cookie', WC()->plugin_url() . '/assets/js/js-cookie/js.cookie' . $suffix . '.js', array(), '2.1.4', true ); diff --git a/plugins/woocommerce/includes/class-wc-frontend-scripts.php b/plugins/woocommerce/includes/class-wc-frontend-scripts.php index c52309655aa..b77615b8451 100644 --- a/plugins/woocommerce/includes/class-wc-frontend-scripts.php +++ b/plugins/woocommerce/includes/class-wc-frontend-scripts.php @@ -234,9 +234,9 @@ class WC_Frontend_Scripts { 'version' => $version, ), 'select2' => array( - 'src' => self::get_asset_url( 'assets/js/selectWoo/selectWoo.full' . $suffix . '.js' ), + 'src' => self::get_asset_url( 'assets/js/select2/select2.full' . $suffix . '.js' ), 'deps' => array( 'jquery' ), - 'version' => '1.0.9-wc.' . $version, + 'version' => '4.0.3-wc.' . $version, ), 'selectWoo' => array( 'src' => self::get_asset_url( 'assets/js/selectWoo/selectWoo.full' . $suffix . '.js' ), From ae6c278e532bd2e1e002e1675a8e57ac52ea1a59 Mon Sep 17 00:00:00 2001 From: "Jorge A. Torres" Date: Thu, 22 Aug 2024 20:06:49 -0300 Subject: [PATCH 083/185] Cherry-pick PR#50881 into trunk (#50897) * Revert "PluginUtil: Add method to get active valid plugins (#48709)" This reverts commit 4d68cd486e07b3dabffe307157ddfe3737eb39c5. * Reintroduce get_all_active_valid_plugins public function after revert (#50885) Retroduce get_all_active_valid_plugins public function after revert --------- Co-authored-by: Naman Malhotra --- plugins/woocommerce/includes/class-wc-install.php | 5 ++--- .../class-wc-rest-system-status-v2-controller.php | 15 ++++++++++----- .../src/Internal/Utilities/PluginInstaller.php | 11 ++--------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/plugins/woocommerce/includes/class-wc-install.php b/plugins/woocommerce/includes/class-wc-install.php index e6d591d8d11..a5915ec3172 100644 --- a/plugins/woocommerce/includes/class-wc-install.php +++ b/plugins/woocommerce/includes/class-wc-install.php @@ -17,7 +17,7 @@ use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchro use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil; use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper as WCConnectionHelper; use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods; -use Automattic\WooCommerce\Utilities\{ OrderUtil, PluginUtil }; +use Automattic\WooCommerce\Utilities\OrderUtil; use Automattic\WooCommerce\Internal\Utilities\PluginInstaller; defined( 'ABSPATH' ) || exit; @@ -1283,8 +1283,7 @@ class WC_Install { return; } - $active_valid_plugins = wc_get_container()->get( PluginUtil::class )->get_all_active_valid_plugins(); - if ( in_array( $legacy_api_plugin, $active_valid_plugins, true ) ) { + if ( in_array( $legacy_api_plugin, wp_get_active_and_valid_plugins(), true ) ) { return; } diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php index 0d663686c33..8c5caec0bd6 100644 --- a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php +++ b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php @@ -13,7 +13,7 @@ defined( 'ABSPATH' ) || exit; use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper; use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories; use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer as Order_DataSynchronizer; -use Automattic\WooCommerce\Utilities\{ LoggingUtil, OrderUtil, PluginUtil }; +use Automattic\WooCommerce\Utilities\{ LoggingUtil, OrderUtil }; /** * System status controller class. @@ -1044,11 +1044,16 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller { return array(); } - $active_valid_plugins = wc_get_container()->get( PluginUtil::class )->get_all_active_valid_plugins(); - $active_plugins_data = array(); + $active_plugins = (array) get_option( 'active_plugins', array() ); + if ( is_multisite() ) { + $network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) ); + $active_plugins = array_merge( $active_plugins, $network_activated_plugins ); + } - foreach ( $active_valid_plugins as $plugin ) { - $data = get_plugin_data( $plugin ); + $active_plugins_data = array(); + + foreach ( $active_plugins as $plugin ) { + $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); $active_plugins_data[] = $this->format_plugin_data( $plugin, $data ); } diff --git a/plugins/woocommerce/src/Internal/Utilities/PluginInstaller.php b/plugins/woocommerce/src/Internal/Utilities/PluginInstaller.php index c3acb6ba4a9..c1985ca81d3 100644 --- a/plugins/woocommerce/src/Internal/Utilities/PluginInstaller.php +++ b/plugins/woocommerce/src/Internal/Utilities/PluginInstaller.php @@ -4,7 +4,7 @@ namespace Automattic\WooCommerce\Internal\Utilities; use Automattic\WooCommerce\Internal\RegisterHooksInterface; use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods; -use Automattic\WooCommerce\Utilities\{ PluginUtil, StringUtil }; +use Automattic\WooCommerce\Utilities\StringUtil; /** * This class allows installing a plugin programmatically. @@ -206,14 +206,7 @@ class PluginInstaller implements RegisterHooksInterface { * @return bool True if WooCommerce is installed and active in the current blog, false otherwise. */ private static function woocommerce_is_active_in_current_site(): bool { - $active_valid_plugins = wc_get_container()->get( PluginUtil::class )->get_all_active_valid_plugins(); - - return ! empty( - array_filter( - $active_valid_plugins, - fn( $plugin ) => substr_compare( $plugin, '/woocommerce.php', -strlen( '/woocommerce.php' ) ) === 0 - ) - ); + return ! empty( array_filter( wp_get_active_and_valid_plugins(), fn( $plugin ) => substr_compare( $plugin, '/woocommerce.php', -strlen( '/woocommerce.php' ) ) === 0 ) ); } /** From 42cdc0e97817b54532bace224b5dc4d50429e9e9 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 23 Aug 2024 11:03:11 +0100 Subject: [PATCH 084/185] Block Checkout: Respect default saved payment method when using tokens (#50481) * activeSavedToken state is unused * Select is_default saved token by default * changelog * Unused objectHasProp --- .../assets/js/data/payment/default-state.ts | 2 -- .../assets/js/data/payment/reducers.ts | 8 +------- .../assets/js/data/payment/test/reducers.js | 9 --------- .../data/payment/utils/set-default-payment-method.ts | 11 ++++++----- .../changelog/fix-48088-select-default-saved-token | 4 ++++ 5 files changed, 11 insertions(+), 23 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-48088-select-default-saved-token diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts b/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts index 884799f2a60..e2fc44a0be5 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts @@ -17,7 +17,6 @@ import { STATUS as PAYMENT_STATUS } from './constants'; export interface PaymentState { status: string; activePaymentMethod: string; - activeSavedToken: string; // Available payment methods are payment methods which have been validated and can make payment. availablePaymentMethods: PlainPaymentMethods; availableExpressPaymentMethods: PlainExpressPaymentMethods; @@ -34,7 +33,6 @@ export interface PaymentState { export const defaultPaymentState: PaymentState = { status: PAYMENT_STATUS.IDLE, activePaymentMethod: '', - activeSavedToken: '', availablePaymentMethods: {}, availableExpressPaymentMethods: {}, savedPaymentMethods: getSetting< diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts b/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts index 4e7502c72d6..d1e2a786c80 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts @@ -2,7 +2,7 @@ * External dependencies */ import type { Reducer } from 'redux'; -import { objectHasProp, PaymentResult } from '@woocommerce/types'; +import { PaymentResult } from '@woocommerce/types'; /** * Internal dependencies @@ -129,14 +129,8 @@ const reducer: Reducer< PaymentState > = ( break; case ACTION_TYPES.SET_ACTIVE_PAYMENT_METHOD: - const activeSavedToken = - typeof state.paymentMethodData === 'object' && - objectHasProp( action.paymentMethodData, 'token' ) - ? action.paymentMethodData.token + '' - : ''; newState = { ...state, - activeSavedToken, activePaymentMethod: action.activePaymentMethod, paymentMethodData: action.paymentMethodData || state.paymentMethodData, diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js b/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js index 5aed26c0e01..63fb4466949 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js +++ b/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js @@ -28,7 +28,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); @@ -55,7 +54,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); } ); @@ -79,7 +77,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); const nextState = reducer( stateWithRegisteredMethod, { @@ -104,7 +101,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); } ); @@ -134,7 +130,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); } ); @@ -162,7 +157,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); const nextState = reducer( stateWithRegisteredMethod, { @@ -187,7 +181,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); } ); @@ -217,7 +210,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); const nextState = reducer( stateWithRegisteredMethod, { @@ -250,7 +242,6 @@ describe( 'paymentMethodDataReducer', () => { shouldSavePaymentMethod: false, errorMessage: '', activePaymentMethod: '', - activeSavedToken: '', incompatiblePaymentMethods: {}, } ); } ); diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/utils/set-default-payment-method.ts b/plugins/woocommerce-blocks/assets/js/data/payment/utils/set-default-payment-method.ts index 71fe94e7e76..907d3d65388 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/utils/set-default-payment-method.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/utils/set-default-payment-method.ts @@ -25,11 +25,13 @@ export const setDefaultPaymentMethod = async ( const savedPaymentMethods = select( PAYMENT_STORE_KEY ).getSavedPaymentMethods(); - + const flatSavedPaymentMethods = Object.keys( savedPaymentMethods ).flatMap( + ( type ) => savedPaymentMethods[ type ] + ); const savedPaymentMethod = - Object.keys( savedPaymentMethods ).flatMap( - ( type ) => savedPaymentMethods[ type ] - )[ 0 ] || undefined; + flatSavedPaymentMethods.find( ( method ) => method.is_default ) || + flatSavedPaymentMethods[ 0 ] || + undefined; if ( savedPaymentMethod ) { const token = savedPaymentMethod.tokenId.toString(); @@ -61,7 +63,6 @@ export const setDefaultPaymentMethod = async ( } dispatch( PAYMENT_STORE_KEY ).__internalSetPaymentIdle(); - dispatch( PAYMENT_STORE_KEY ).__internalSetActivePaymentMethod( paymentMethodKeys[ 0 ] ); diff --git a/plugins/woocommerce/changelog/fix-48088-select-default-saved-token b/plugins/woocommerce/changelog/fix-48088-select-default-saved-token new file mode 100644 index 00000000000..a126d93c503 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-48088-select-default-saved-token @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Default saved payment method is now respected by block checkout. From eef4749d978752d69ecf064c81ed87fdab88ab18 Mon Sep 17 00:00:00 2001 From: Seghir Nadir Date: Fri, 23 Aug 2024 12:37:33 +0200 Subject: [PATCH 085/185] Ensure translation is loaded for new shared file in Checkout Block (#50892) * Ensure translation is loaded for new shared file * add other files * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions --- .../50892-fix-translation-not-loading-for-new-shared-file | 4 ++++ plugins/woocommerce/src/Blocks/AssetsController.php | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 plugins/woocommerce/changelog/50892-fix-translation-not-loading-for-new-shared-file diff --git a/plugins/woocommerce/changelog/50892-fix-translation-not-loading-for-new-shared-file b/plugins/woocommerce/changelog/50892-fix-translation-not-loading-for-new-shared-file new file mode 100644 index 00000000000..93287f6d3df --- /dev/null +++ b/plugins/woocommerce/changelog/50892-fix-translation-not-loading-for-new-shared-file @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Ensure translation is fully loaded for certain parts of Checkout block. \ No newline at end of file diff --git a/plugins/woocommerce/src/Blocks/AssetsController.php b/plugins/woocommerce/src/Blocks/AssetsController.php index 1bb55c0f0c1..13236dc8145 100644 --- a/plugins/woocommerce/src/Blocks/AssetsController.php +++ b/plugins/woocommerce/src/Blocks/AssetsController.php @@ -64,11 +64,11 @@ final class AssetsController { $this->api->register_script( 'wc-price-format', 'assets/client/blocks/price-format.js', array(), false ); // Vendor scripts for blocks frontends (not including cart and checkout). - $this->api->register_script( 'wc-blocks-frontend-vendors', $this->api->get_block_asset_build_path( 'wc-blocks-frontend-vendors-frontend' ), array(), false ); + $this->api->register_script( 'wc-blocks-frontend-vendors', $this->api->get_block_asset_build_path( 'wc-blocks-frontend-vendors-frontend' ), array(), true ); // Cart and checkout frontend scripts. - $this->api->register_script( 'wc-cart-checkout-vendors', $this->api->get_block_asset_build_path( 'wc-cart-checkout-vendors-frontend' ), array(), false ); - $this->api->register_script( 'wc-cart-checkout-base', $this->api->get_block_asset_build_path( 'wc-cart-checkout-base-frontend' ), array(), false ); + $this->api->register_script( 'wc-cart-checkout-vendors', $this->api->get_block_asset_build_path( 'wc-cart-checkout-vendors-frontend' ), array(), true ); + $this->api->register_script( 'wc-cart-checkout-base', $this->api->get_block_asset_build_path( 'wc-cart-checkout-base-frontend' ), array(), true ); $this->api->register_script( 'wc-blocks-checkout', 'assets/client/blocks/blocks-checkout.js' ); $this->api->register_script( 'wc-blocks-components', 'assets/client/blocks/blocks-components.js' ); From 091141218ed0f27e717f479f4bac52e8b594e5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Rinc=C3=B3n?= Date: Fri, 23 Aug 2024 13:27:57 +0200 Subject: [PATCH 086/185] CYS - Move the `private/patterns` endpoint to woocommerce admin API (#50400) * CYS - Move the ai/store-title endpoint to woocommerce admin api * Add middleware and callback * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint error * CYS - Move the ai/business-description endpoint to woocommerce admin API * CYS - Move the ai/store-info endpoint to woocommerce admin API * Update endpoint * CYS - Move the ai/images endpoint to woocommerce admin API * CYS - Move the `ai/patterns` endpoint to woocommerce admin API * CYS - Move the `ai/product` endpoint to woocommerce admin API * CYS - Move the `ai/products` endpoint to woocommerce admin API * CYS - Move the `private/patterns` endpoint to woocommerce admin API * Remove unnecessary variable * Replace endpoint * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint errors * Fix some feedback * Refactor route to return an error not an exception and add tests * Fix lint errors --------- Co-authored-by: github-actions --- .../assembler-hub/opt-in/opt-in.tsx | 2 +- ...sidebar-navigation-screen-homepage-ptk.tsx | 2 +- .../design-without-ai/services.ts | 2 +- .../client/customize-store/intro/services.ts | 2 +- ...0400-48150-move-patterns-endpoint-to-admin | 4 + plugins/woocommerce/src/Admin/API/Init.php | 1 + .../woocommerce/src/Admin/API/Patterns.php | 93 ++++++++++++++ .../src/StoreApi/RoutesController.php | 5 +- .../src/StoreApi/SchemaController.php | 1 - .../StoreApi/Schemas/V1/PatternsSchema.php | 43 ------- .../assembler/homepage.spec.js | 2 +- .../tests/php/src/Admin/API/PatternsTest.php | 121 ++++++++++++++++++ .../src/Blocks/StoreApi/Routes/Patterns.php | 56 -------- 13 files changed, 225 insertions(+), 109 deletions(-) create mode 100644 plugins/woocommerce/changelog/50400-48150-move-patterns-endpoint-to-admin create mode 100644 plugins/woocommerce/src/Admin/API/Patterns.php delete mode 100644 plugins/woocommerce/src/StoreApi/Schemas/V1/PatternsSchema.php create mode 100644 plugins/woocommerce/tests/php/src/Admin/API/PatternsTest.php delete mode 100644 plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Patterns.php diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/opt-in.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/opt-in.tsx index 23758b5e218..584b9d7bcd7 100644 --- a/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/opt-in.tsx +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/opt-in.tsx @@ -49,7 +49,7 @@ export const OptInSubscribe = () => { await apiFetch< { success: boolean; } >( { - path: `/wc/private/patterns`, + path: '/wc-admin/patterns', method: 'POST', } ); }; diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx index e3b0c875c3f..593f12e7b21 100644 --- a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx @@ -264,7 +264,7 @@ export const SidebarNavigationScreenHomepagePTK = ( {
        diff --git a/packages/js/product-editor/src/blocks/product-fields/downloads/downloads-menu/style.scss b/packages/js/product-editor/src/blocks/product-fields/downloads/downloads-menu/style.scss index fe56bd2c248..0cec19b4642 100644 --- a/packages/js/product-editor/src/blocks/product-fields/downloads/downloads-menu/style.scss +++ b/packages/js/product-editor/src/blocks/product-fields/downloads/downloads-menu/style.scss @@ -1,5 +1,5 @@ .woocommerce-downloads-menu { - &__toogle { + &__toggle { flex-direction: row-reverse; > span { diff --git a/packages/js/product-editor/src/components/variations-table/styles.scss b/packages/js/product-editor/src/components/variations-table/styles.scss index 9e78670f16a..a58f35e4c3f 100644 --- a/packages/js/product-editor/src/components/variations-table/styles.scss +++ b/packages/js/product-editor/src/components/variations-table/styles.scss @@ -162,7 +162,7 @@ gap: $gap-smaller; margin-right: $gap-smallest; - .variations-actions-menu__toogle:disabled { + .variations-actions-menu__toggle:disabled { cursor: not-allowed; } diff --git a/packages/js/product-editor/src/components/variations-table/variation-actions-menus/multiple-update-menu.tsx b/packages/js/product-editor/src/components/variations-table/variation-actions-menus/multiple-update-menu.tsx index 8c5f6e74fa7..12c3eb0b0a4 100644 --- a/packages/js/product-editor/src/components/variations-table/variation-actions-menus/multiple-update-menu.tsx +++ b/packages/js/product-editor/src/components/variations-table/variation-actions-menus/multiple-update-menu.tsx @@ -35,7 +35,7 @@ export function MultipleUpdateMenu( { icon={ isOpen ? chevronUp : chevronDown } variant="secondary" onClick={ onToggle } - className="variations-actions-menu__toogle" + className="variations-actions-menu__toggle" > { __( 'Quick update', 'woocommerce' ) } diff --git a/packages/js/product-editor/src/components/variations-table/variation-actions-menus/styles.scss b/packages/js/product-editor/src/components/variations-table/variation-actions-menus/styles.scss index 99143614edc..7956e681575 100644 --- a/packages/js/product-editor/src/components/variations-table/variation-actions-menus/styles.scss +++ b/packages/js/product-editor/src/components/variations-table/variation-actions-menus/styles.scss @@ -1,5 +1,5 @@ .variations-actions-menu { - &__toogle { + &__toggle { flex-direction: row-reverse; > span { From 53be5776f473ec1b8e530e701b4198e0ccc748d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Wytr=C4=99bowicz?= Date: Sun, 25 Aug 2024 19:56:59 +0200 Subject: [PATCH 100/185] Remove the usage of `` as it has no effect (#50751) The support for such property was removed in woocommerce/woocommerce-admin#4858 ~4 years ago. Co-authored-by: github-actions --- .../client/analytics/components/report-summary/test/index.js | 2 +- .../client/analytics/report/categories/index.js | 1 - .../client/analytics/report/coupons/index.js | 1 - .../client/analytics/report/products/index.js | 1 - .../woocommerce-admin/client/analytics/report/taxes/index.js | 1 - .../client/analytics/report/variations/index.js | 1 - .../changelog/50751-fix-isRequesting-report-summary | 4 ++++ 7 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 plugins/woocommerce/changelog/50751-fix-isRequesting-report-summary diff --git a/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js b/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js index 970dee29eec..697071d8b69 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-summary/test/index.js @@ -134,7 +134,7 @@ describe( 'ReportSummary', () => { ).toBeInTheDocument(); } ); - test( 'should display SummaryListPlaceholder when isRequesting is true', () => { + test( 'should display SummaryListPlaceholder when summaryData.isRequesting is true', () => { const { container } = renderChart( 'number', null, null, false, true ); expect( diff --git a/plugins/woocommerce-admin/client/analytics/report/categories/index.js b/plugins/woocommerce-admin/client/analytics/report/categories/index.js index 904f1e1bac1..02110c765da 100644 --- a/plugins/woocommerce-admin/client/analytics/report/categories/index.js +++ b/plugins/woocommerce-admin/client/analytics/report/categories/index.js @@ -69,7 +69,6 @@ class CategoriesReport extends Component { { mode={ mode } charts={ charts } endpoint="variations" - isRequesting={ isRequesting } query={ chartQuery } selectedChart={ getSelectedChart( query.chart, charts ) } filters={ filters } diff --git a/plugins/woocommerce/changelog/50751-fix-isRequesting-report-summary b/plugins/woocommerce/changelog/50751-fix-isRequesting-report-summary new file mode 100644 index 00000000000..052457d7f62 --- /dev/null +++ b/plugins/woocommerce/changelog/50751-fix-isRequesting-report-summary @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak + +Remove the usage of `ReportSummary`s `isRequesting` property as it has no effect. \ No newline at end of file From e6b1cac49c0d252df930425c7936b12e38bb2a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 26 Aug 2024 09:46:32 +0200 Subject: [PATCH 101/185] Update compatibility layer logic so it detects blocks inside patterns (#50595) * Detect Legacy Template block when it's inside a pattern * Detect Single Product blocks when they are inside a pattern * Typo * Remove empty error messages * Fix wrong variable passed to parse_blocks() * Remove unnecessary parameters * Add tests to check if the Single Product template contents are updated when the Legacy Template is in the content * Add changelog file * Linting * Typo * Make sure the correct template is used when deciding whether to disable the compatibility layer or not * Simplify code * Remove duplicate content in tests * Simplify single product slug logic * Add an extra test to make sure Single Product template logic doesn't leak into other templates * Linting --------- Co-authored-by: Sam Seay --- .../fix-50055-compatibility-layer-patterns | 4 + .../AbstractTemplateCompatibility.php | 4 +- .../Templates/SingleProductTemplate.php | 32 ++- .../SingleProductTemplateCompatibility.php | 30 +-- .../src/Blocks/Utils/BlockTemplateUtils.php | 41 +++- ...ingleProductTemplateCompatibilityTests.php | 106 ++++++-- .../Templates/SingleProductTemplateTests.php | 226 ++++++++++++++++-- 7 files changed, 376 insertions(+), 67 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns diff --git a/plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns b/plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns new file mode 100644 index 00000000000..e6811df2b13 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Update the logic that conditionally activates the compatibility layer in WooCommerce block templates so it detects blocks inside patterns diff --git a/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php b/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php index 3d622a345c2..b06892291c3 100644 --- a/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php +++ b/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php @@ -61,9 +61,9 @@ abstract class AbstractTemplateCompatibility { * @since 7.6.0 * @param boolean. */ - $is_disabled_compatility_layer = apply_filters( 'woocommerce_disable_compatibility_layer', false ); + $is_disabled_compatibility_layer = apply_filters( 'woocommerce_disable_compatibility_layer', false ); - if ( $is_disabled_compatility_layer ) { + if ( $is_disabled_compatibility_layer ) { return $block_content; } diff --git a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php index 942f807422f..69ef307fc3a 100644 --- a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php +++ b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php @@ -23,7 +23,7 @@ class SingleProductTemplate extends AbstractTemplate { */ public function init() { add_action( 'template_redirect', array( $this, 'render_block_template' ) ); - add_filter( 'get_block_templates', array( $this, 'update_single_product_content' ), 11, 3 ); + add_filter( 'get_block_templates', array( $this, 'update_single_product_content' ), 11, 1 ); } /** @@ -51,13 +51,31 @@ class SingleProductTemplate extends AbstractTemplate { if ( ! is_embed() && is_singular( 'product' ) ) { global $post; - $valid_slugs = array( self::SLUG ); - if ( 'product' === $post->post_type && $post->post_name ) { + $valid_slugs = array( self::SLUG ); + $single_product_slug = 'product' === $post->post_type && $post->post_name ? 'single-product-' . $post->post_name : ''; + if ( $single_product_slug ) { $valid_slugs[] = 'single-product-' . $post->post_name; } $templates = get_block_templates( array( 'slug__in' => $valid_slugs ) ); - if ( isset( $templates[0] ) && BlockTemplateUtils::template_has_legacy_template_block( $templates[0] ) ) { + if ( count( $templates ) === 0 ) { + return; + } + + // Use the first template by default. + $template = $templates[0]; + + // Check if there is a template matching the slug `single-product-{post_name}`. + if ( count( $valid_slugs ) > 1 && count( $templates ) > 1 ) { + foreach ( $templates as $t ) { + if ( $single_product_slug === $t->slug ) { + $template = $t; + break; + } + } + } + + if ( isset( $template ) && BlockTemplateUtils::template_has_legacy_template_block( $template ) ) { add_filter( 'woocommerce_disable_compatibility_layer', '__return_true' ); } @@ -68,12 +86,10 @@ class SingleProductTemplate extends AbstractTemplate { /** * Add the block template objects to be used. * - * @param array $query_result Array of template objects. - * @param array $query Optional. Arguments to retrieve templates. - * @param string $template_type wp_template or wp_template_part. + * @param array $query_result Array of template objects. * @return array */ - public function update_single_product_content( $query_result, $query, $template_type ) { + public function update_single_product_content( $query_result ) { $query_result = array_map( function ( $template ) { if ( str_contains( $template->slug, self::SLUG ) ) { diff --git a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php index 05191bcbdbb..f48d7697798 100644 --- a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php +++ b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php @@ -1,6 +1,8 @@ get_registered( $block['attrs']['slug'] ); + $pattern_blocks = parse_blocks( $pattern['content'] ); + + if ( self::has_block_including_patterns( $block_names, $pattern_blocks ) ) { + return true; + } + } + } + + return false; + } + /** * Returns whether the passed `$template` has the legacy template block. * @@ -703,7 +736,13 @@ class BlockTemplateUtils { * @return boolean */ public static function template_has_legacy_template_block( $template ) { - return has_block( 'woocommerce/legacy-template', $template->content ); + if ( has_block( 'woocommerce/legacy-template', $template->content ) ) { + return true; + } + + $blocks = parse_blocks( $template->content ); + + return self::has_block_including_patterns( array( 'woocommerce/legacy-template' ), $blocks ); } /** diff --git a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php index 4ab7388ed9c..e67d08b5563 100644 --- a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php +++ b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php @@ -37,10 +37,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -72,10 +72,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -155,10 +155,80 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); + } + + /** + * Test that the Single Product Template is wrapped in a div with the correct class if it contains a pattern that contains a block related to the Single Product Template. + */ + public function test_add_compatibility_layer_if_contains_pattern_with_single_product_blocks() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '', + ) + ); + + $default_single_product_template = ' + + + '; + + $expected_single_product_template = ' + + +
        + +
        + + '; + + $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); + + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); + + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); + } + + /** + * Test that the Single Product Template is wrapped in a div with the correct class if it contains a pattern that contains an inner block related to the Single Product Template. + */ + public function test_add_compatibility_layer_if_contains_pattern_with_inner_single_product_blocks() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '
        ', + ) + ); + + $default_single_product_template = ' + + + '; + + $expected_single_product_template = ' + + +
        + +
        + + '; + + $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); + + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); + + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -222,10 +292,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -251,10 +321,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } @@ -281,10 +351,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -322,10 +392,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -359,10 +429,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -398,9 +468,9 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } } diff --git a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php index 7649173e24a..634df6d181c 100644 --- a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php +++ b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php @@ -11,6 +11,203 @@ use \WP_UnitTestCase; */ class SingleProductTemplateTests extends WP_UnitTestCase { + /** + * Test that the Product Catalog template content isn't updated mistakenly. + * In other words, make sure the Single Product template logic doesn't leak + * into other templates. + * + */ + public function test_dont_update_single_product_content_for_other_templates() { + $single_product_template = new SingleProductTemplate(); + $default_product_catalog_template_content = ' + + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'archive-product'; + $template->title = 'Product Catalog'; + $template->content = $default_product_catalog_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $this->assertEquals( + $default_product_catalog_template_content, + $result[0]->content + ); + } + + /** + * Test that the Single Product template content isn't updated if it + * contains the Legacy Template block. + * + */ + public function test_dont_update_single_product_content_with_legacy_template() { + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $this->assertEquals( + $default_single_product_template_content, + $result[0]->content + ); + } + + /** + * Test that the Single Product template content is updated if it doesn't + * contain the Legacy Template block. + * + */ + public function test_update_single_product_content_with_legacy_template() { + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + $expected_single_product_template_content = ' + + +
        + +
        + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $expected_single_product_template_without_whitespace = preg_replace( + '/\s+/', + '', + $expected_single_product_template_content + ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result[0]->content ); + + $this->assertEquals( + $expected_single_product_template_without_whitespace, + $result_without_whitespace + ); + } + + /** + * Test that the Single Product template content isn't updated if it + * contains a pattern with the Legacy Template block. + * + */ + public function test_dont_update_single_product_content_with_legacy_template_inside_a_pattern() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '', + ) + ); + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $this->assertEquals( + $default_single_product_template_content, + $result[0]->content + ); + } + + /** + * Test that the Single Product template content is updated if it doesn't + * contain the Legacy Template block. + * + */ + public function test_update_single_product_content_with_legacy_template_inside_a_pattern() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '', + ) + ); + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + $expected_single_product_template_content = ' + + +
        + +
        + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $expected_single_product_template_without_whitespace = preg_replace( + '/\s+/', + '', + $expected_single_product_template_content + ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result[0]->content ); + + $this->assertEquals( + $expected_single_product_template_without_whitespace, + $result_without_whitespace + ); + } + /** * Test that the password form isn't added to the Single Product Template. * @@ -38,7 +235,7 @@ class SingleProductTemplateTests extends WP_UnitTestCase { $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', @@ -46,9 +243,8 @@ class SingleProductTemplateTests extends WP_UnitTestCase { ); $this->assertEquals( - $result_without_withespace, - $expected_single_product_template_without_whitespace, - '' + $result_without_whitespace, + $expected_single_product_template_without_whitespace ); } @@ -81,11 +277,11 @@ class SingleProductTemplateTests extends WP_UnitTestCase { $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); - $result_without_withespace_without_custom_pwbox_ids = preg_replace( + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace_without_custom_pwbox_ids = preg_replace( '/pwbox-\d+/', '', - $result_without_withespace + $result_without_whitespace ); $expected_single_product_template_without_whitespace = preg_replace( @@ -101,9 +297,8 @@ class SingleProductTemplateTests extends WP_UnitTestCase { ); $this->assertEquals( - $result_without_withespace_without_custom_pwbox_ids, - $expected_single_product_template_without_whitespace_without_custom_pwbox_ids, - '' + $result_without_whitespace_without_custom_pwbox_ids, + $expected_single_product_template_without_whitespace_without_custom_pwbox_ids ); } @@ -219,11 +414,11 @@ class SingleProductTemplateTests extends WP_UnitTestCase { $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); - $result_without_withespace_without_custom_pwbox_ids = preg_replace( + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace_without_custom_pwbox_ids = preg_replace( '/pwbox-\d+/', '', - $result_without_withespace + $result_without_whitespace ); $expected_single_product_template_without_whitespace = preg_replace( @@ -239,9 +434,8 @@ class SingleProductTemplateTests extends WP_UnitTestCase { ); $this->assertEquals( - $result_without_withespace_without_custom_pwbox_ids, - $expected_single_product_template_without_whitespace_without_custom_pwbox_ids, - '' + $result_without_whitespace_without_custom_pwbox_ids, + $expected_single_product_template_without_whitespace_without_custom_pwbox_ids ); } } From 9e40710482d1b28f6f53c627af44a984c741a5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Rinc=C3=B3n?= Date: Mon, 26 Aug 2024 09:58:54 +0200 Subject: [PATCH 102/185] CYS - Remove usage of `prepare_item_for_response` function in `Images` endpoint (#50923) * Remove usage of `prepare_item_for_response` function * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions --- .../changelog/50923-fix-remove-non-existing-method | 4 ++++ plugins/woocommerce/src/Admin/API/AI/Images.php | 11 ++++------- 2 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 plugins/woocommerce/changelog/50923-fix-remove-non-existing-method diff --git a/plugins/woocommerce/changelog/50923-fix-remove-non-existing-method b/plugins/woocommerce/changelog/50923-fix-remove-non-existing-method new file mode 100644 index 00000000000..c87d77f7127 --- /dev/null +++ b/plugins/woocommerce/changelog/50923-fix-remove-non-existing-method @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +CYS - Remove usage of `prepare_item_for_response` function in `Images` endpoint. \ No newline at end of file diff --git a/plugins/woocommerce/src/Admin/API/AI/Images.php b/plugins/woocommerce/src/Admin/API/AI/Images.php index 5acd60e2030..8ac0f7023f4 100644 --- a/plugins/woocommerce/src/Admin/API/AI/Images.php +++ b/plugins/woocommerce/src/Admin/API/AI/Images.php @@ -65,13 +65,10 @@ class Images extends AIEndpoint { if ( $last_business_description === $business_description ) { return rest_ensure_response( - $this->prepare_item_for_response( - array( - 'ai_content_generated' => true, - 'images' => array(), - ), - $request - ) + array( + 'ai_content_generated' => true, + 'images' => array(), + ), ); } From b4322595c587edae333672717e10f17f95367ef9 Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Mon, 26 Aug 2024 16:53:05 +0800 Subject: [PATCH 103/185] Hide payments recommendation when no extensions are available (#50949) * Hide payment recommendations when no extensions are available * Changelog --- .../client/payments/payment-recommendations.tsx | 4 ++++ .../fix-hide-payments-recommendation-when-no-extensions | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-hide-payments-recommendation-when-no-extensions diff --git a/plugins/woocommerce-admin/client/payments/payment-recommendations.tsx b/plugins/woocommerce-admin/client/payments/payment-recommendations.tsx index 1425d26fab0..798eb01fde5 100644 --- a/plugins/woocommerce-admin/client/payments/payment-recommendations.tsx +++ b/plugins/woocommerce-admin/client/payments/payment-recommendations.tsx @@ -205,6 +205,10 @@ const PaymentRecommendations: React.FC = () => { }; } ); + if ( pluginsList.length === 0 ) { + return null; + } + return ( diff --git a/plugins/woocommerce/changelog/fix-hide-payments-recommendation-when-no-extensions b/plugins/woocommerce/changelog/fix-hide-payments-recommendation-when-no-extensions new file mode 100644 index 00000000000..169df53a6f7 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-hide-payments-recommendation-when-no-extensions @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Hide payment recommendations when no extensions are available From 08f724b8d894653b2af0e5f95968260120a5a89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 26 Aug 2024 13:18:28 +0200 Subject: [PATCH 104/185] Improve the tabs focus style in the Product Details block with Minimal style variation (#50880) * Improve the tabs focus style in the Product Details block with Minimal style variation * Add changelog file * Remove direct child selector --- .../product-elements/product-details/style.scss | 12 ++++++++++-- ...mprove-product-details-minimal-style-focus-styles | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-50550-improve-product-details-minimal-style-focus-styles diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/product-details/style.scss b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/product-details/style.scss index 5a426110c5d..ee76bea98ec 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/product-details/style.scss +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/product-details/style.scss @@ -11,6 +11,7 @@ html body .wp-block-woocommerce-product-details.is-style-minimal { padding: 0; border-bottom-width: 0; border-bottom-color: inherit; /* Backward compatibility for TT3, TT2. */ + overflow: visible; &::after, &::before { @@ -26,14 +27,14 @@ html body .wp-block-woocommerce-product-details.is-style-minimal { border-bottom-width: 2px; border-radius: 0; margin: 0; - padding: 0 1em; + padding: 0; display: inline-block; float: none; /* Backward compatibility for TT3, TT2. */ font-weight: bold; opacity: 0.65; a { - padding: 0.5em 0; + padding: 0.5em 1em; color: inherit; border: none; text-shadow: none; @@ -42,6 +43,7 @@ html body .wp-block-woocommerce-product-details.is-style-minimal { } &:hover, + &:focus-within, &.active { color: inherit; background: inherit; @@ -55,6 +57,12 @@ html body .wp-block-woocommerce-product-details.is-style-minimal { } } + /* Remove default focus styles in favor of the ones we defined above. */ + &:focus:not(:focus-visible), + a:focus:not(:focus-visible) { + outline: none; + } + @media only screen and ( max-width: 768px ) { display: block; border-left-width: 2px; diff --git a/plugins/woocommerce/changelog/fix-50550-improve-product-details-minimal-style-focus-styles b/plugins/woocommerce/changelog/fix-50550-improve-product-details-minimal-style-focus-styles new file mode 100644 index 00000000000..a703bf3d9e8 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50550-improve-product-details-minimal-style-focus-styles @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Improve the tabs focus style in the Product Details block with Minimal style variation From 99c1980b942949e0c206695db802646ba90797c5 Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Mon, 26 Aug 2024 20:18:48 +0800 Subject: [PATCH 105/185] Show payments recommendation on settings payment main page (#50947) * Show payments recommendation when main settings element is found * Changelog * Revert to old logic instead --- .../payments/payment-recommendations-wrapper.tsx | 14 +++++--------- ...ow-recommendation-on-settings-payment-main-page | 4 ++++ 2 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-show-recommendation-on-settings-payment-main-page diff --git a/plugins/woocommerce-admin/client/payments/payment-recommendations-wrapper.tsx b/plugins/woocommerce-admin/client/payments/payment-recommendations-wrapper.tsx index 1a57546b462..d00e034175c 100644 --- a/plugins/woocommerce-admin/client/payments/payment-recommendations-wrapper.tsx +++ b/plugins/woocommerce-admin/client/payments/payment-recommendations-wrapper.tsx @@ -21,15 +21,11 @@ export const PaymentRecommendations: React.FC< EmbeddedBodyProps > = ( { tab, section, } ) => { - if ( page === 'wc-settings' && tab === 'checkout' && ! section ) { - if ( - window?.wcAdminFeatures?.[ - 'reactify-classic-payments-settings' - ] === true - ) { - return null; - } - + if ( + page === 'wc-settings' && + tab === 'checkout' && + ( ! section || section === 'main' ) + ) { return ( diff --git a/plugins/woocommerce/changelog/fix-show-recommendation-on-settings-payment-main-page b/plugins/woocommerce/changelog/fix-show-recommendation-on-settings-payment-main-page new file mode 100644 index 00000000000..b45252f8239 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-show-recommendation-on-settings-payment-main-page @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Show payments recommendation when main settings element is found From 30ae60b27336ce050bd69ecf6e2707e7f593a76a Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Mon, 26 Aug 2024 20:57:03 +0800 Subject: [PATCH 106/185] Fix flaky remote logging PHP unit test (#50950) * Fix flaky remote logging test_remote_logging_allowed() test * Fix Undefined variable $enabled * Add changelog --- .../changelog/fix-flaky-remote-logging-test | 4 ++ .../src/Internal/Logging/RemoteLoggerTest.php | 39 ++++++++++++------- 2 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-flaky-remote-logging-test diff --git a/plugins/woocommerce/changelog/fix-flaky-remote-logging-test b/plugins/woocommerce/changelog/fix-flaky-remote-logging-test new file mode 100644 index 00000000000..d0a9491c758 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-flaky-remote-logging-test @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Fix flaky remote logging PHP unit test diff --git a/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php b/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php index d4af6c893fe..7133f38f5ef 100644 --- a/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php +++ b/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php @@ -24,8 +24,7 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { */ public function setUp(): void { parent::setUp(); - $this->sut = wc_get_container()->get( RemoteLogger::class ); - WC()->version = '9.2.0'; + $this->sut = wc_get_container()->get( RemoteLogger::class ); } /** @@ -37,6 +36,7 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { $this->cleanup_filters(); delete_option( 'woocommerce_feature_remote_logging_enabled' ); delete_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT ); + delete_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY ); global $wpdb; $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_rate_limits" ); WC_Cache_Helper::invalidate_cache_group( WC_Rate_Limiter::CACHE_GROUP ); @@ -90,21 +90,34 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { */ public function remote_logging_disallowed_provider() { return array( - 'feature flag disabled' => array( + 'feature flag disabled' => array( 'condition' => 'feature flag disabled', 'setup' => fn() => update_option( 'woocommerce_feature_remote_logging_enabled', 'no' ), ), - 'tracking opted out' => array( + 'tracking opted out' => array( 'condition' => 'tracking opted out', 'setup' => fn() => add_filter( 'option_woocommerce_allow_tracking', fn() => 'no' ), ), - 'outdated version' => array( - 'condition' => 'outdated version', - 'setup' => fn() => WC()->version = '9.0.0', - ), - 'high variant assignment' => array( - 'condition' => 'high variant assignment', - 'setup' => fn() => add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 15 ), + 'outdated version' => array( + 'condition' => 'outdated version', + 'setup' => function () { + $version = WC()->version; + $next_version = implode( + '.', + array_map( + function ( $n, $i ) { + return 0 === $i ? $n + 1 : 0; + }, + explode( '.', $version ), + array_keys( explode( '.', $version ) ) + ) + ); + set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, $next_version ); + }, + 'high variant assignment' => array( + 'condition' => 'high variant assignment', + 'setup' => fn() => add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 15 ), + ), ), ); } @@ -410,9 +423,9 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 5 ); add_filter( 'plugins_api', - function ( $result, $action, $args ) { + function ( $result, $action, $args ) use ( $enabled ) { if ( 'plugin_information' === $action && 'woocommerce' === $args->slug ) { - return (object) array( 'version' => '9.2.0' ); + return (object) array( 'version' => $enabled ? WC()->version : '9.0.0' ); } return $result; }, From 70faf5bba24f87ffae91b11068a673894d9adc1f Mon Sep 17 00:00:00 2001 From: Corey McKrill <916023+coreymckrill@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:17:36 -0700 Subject: [PATCH 107/185] Checkout: prevent error from get_value method when WC has not been properly initialized (#50692) * Ensure WC's customer and cart props are initialized If the customer or cart property of the main WooCommerce class is accessed before the `woocommerce_init` action has fired, those properties will be `null` instead of containing their respective classes, which can cause a fatal error if you then try to access a method on one of the classes. This makes sure the props will always return a class. Fixes #50245 * Revert "Ensure WC's customer and cart props are initialized" This approach unexpectedly breaks a lot of things... This reverts commit 310fd2c11833e279ea5a001c7aed38fda605af9c. * Alternate solution The attempt to fix the problem wholistically ended up causing a lot of things to break, so this is the band-aid approach instead. * Add changelog file * Remove unnecessary assignment to global POST var This was polluting the results of the new test, causing it to fail. --- .../fix-50245-fatal-error-checkout-customer | 4 +++ .../includes/class-wc-checkout.php | 2 +- .../php/includes/class-wc-checkout-test.php | 30 ++++++++++++------- 3 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-50245-fatal-error-checkout-customer diff --git a/plugins/woocommerce/changelog/fix-50245-fatal-error-checkout-customer b/plugins/woocommerce/changelog/fix-50245-fatal-error-checkout-customer new file mode 100644 index 00000000000..4c7ba4fcea1 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50245-fatal-error-checkout-customer @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Prevent an error in the WC_Checkout class when WooCommerce has not been properly initialized yet diff --git a/plugins/woocommerce/includes/class-wc-checkout.php b/plugins/woocommerce/includes/class-wc-checkout.php index 943746642e8..3c920e598a4 100644 --- a/plugins/woocommerce/includes/class-wc-checkout.php +++ b/plugins/woocommerce/includes/class-wc-checkout.php @@ -1357,7 +1357,7 @@ class WC_Checkout { if ( is_callable( array( $customer_object, "get_$input" ) ) ) { $value = $customer_object->{"get_$input"}(); - } elseif ( $customer_object->meta_exists( $input ) ) { + } elseif ( is_callable( array( $customer_object, 'meta_exists' ) ) && $customer_object->meta_exists( $input ) ) { $value = $customer_object->get_meta( $input, true ); } diff --git a/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php b/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php index ef7a26d47c7..2c8b7406ad9 100644 --- a/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php +++ b/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php @@ -46,12 +46,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case { * @param bool $expect_error_message_for_shipping_country True to expect an error to be generated for the shipping country. */ public function test_validate_posted_data_adds_error_for_non_existing_country( $ship_to_different_address, $expect_error_message_for_shipping_country ) { - $_POST = array( + $data = array( 'billing_country' => 'XX', 'shipping_country' => 'YY', 'ship_to_different_address' => $ship_to_different_address, ); - $data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing add_filter( 'woocommerce_cart_needs_shipping_address', @@ -75,12 +74,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case { * @testdox the customer notes are correctly sanitized. */ public function test_order_notes() { - $_POST = array( + $data = array( 'ship_to_different_address' => false, 'order_comments' => 'This text should not save inside an anchor.', 'payment_method' => 'bacs', ); - $data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing $errors = new WP_Error(); @@ -108,12 +106,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case { * @param bool $ship_to_different_address True to simulate shipping to a different address than the billing address. */ public function test_validate_posted_data_does_not_add_error_for_existing_country( $ship_to_different_address ) { - $_POST = array( + $data = array( 'billing_country' => 'ES', 'shipping_country' => 'ES', 'ship_to_different_address' => $ship_to_different_address, ); - $data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing $errors = new WP_Error(); @@ -132,12 +129,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case { * @param bool $ship_to_different_address True to simulate shipping to a different address than the billing address. */ public function test_validate_posted_data_does_not_add_error_for_empty_country( $ship_to_different_address ) { - $_POST = array( + $data = array( 'billing_country' => '', 'shipping_country' => '', 'ship_to_different_address' => $ship_to_different_address, ); - $data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing $errors = new WP_Error(); @@ -186,12 +182,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case { ) ); - $_POST = array( + $data = array( 'billing_country' => $country, 'shipping_country' => $country, 'ship_to_different_address' => false, ); - $data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing $errors = new WP_Error(); @@ -202,5 +197,20 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case { $errors->get_error_message( 'shipping' ) ); } + + /** + * @testdox If the WooCommerce class's customer object is null (like if WC has not been fully initialized yet), + * calling WC_Checkout::get_value should not throw an error. + */ + public function test_get_value_no_error_on_null_customer() { + $sut = WC_Checkout::instance(); + + $orig_customer = WC()->customer; + WC()->customer = null; + + $this->assertNull( $sut->get_value( 'billing_country' ) ); + + WC()->customer = $orig_customer; + } } From 4142afbc054ee8e23b1ff40852ad93d912e0f35e Mon Sep 17 00:00:00 2001 From: Naman Malhotra Date: Tue, 27 Aug 2024 00:06:29 +0530 Subject: [PATCH 108/185] Update stable tag to 9.2.3 (#50965) woorelease: Update stable tag to 9.2.3 --- plugins/woocommerce/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/readme.txt b/plugins/woocommerce/readme.txt index 986ef663a9f..d3730c2db5b 100644 --- a/plugins/woocommerce/readme.txt +++ b/plugins/woocommerce/readme.txt @@ -4,7 +4,7 @@ Tags: online store, ecommerce, shop, shopping cart, sell online Requires at least: 6.5 Tested up to: 6.6 Requires PHP: 7.4 -Stable tag: 9.2.2 +Stable tag: 9.2.3 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html From 5c58d9d50cd61367f1f682ca5709eb53efdedcac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2024 01:58:28 +0700 Subject: [PATCH 109/185] Update changelog.txt from release 9.2.3 (#50967) Prep trunk post release 9.2.3 Co-authored-by: WooCommerce Bot --- changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.txt b/changelog.txt index ed1be0eb305..e34b03260d4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,12 @@ == Changelog == += 9.2.3 2024-08-26 = + +**WooCommerce** + +* Fix - Ensure translation is fully loaded for certain parts of Checkout block. [#50892](https://github.com/woocommerce/woocommerce/pull/50892) + + = 9.2.2 2024-08-22 = **WooCommerce** From cc07a5f90216ba4226bc8c4ea588c25fc7c57daf Mon Sep 17 00:00:00 2001 From: Roy Ho Date: Mon, 26 Aug 2024 19:57:01 -0700 Subject: [PATCH 110/185] [Experimental] Price filter: fix range slider update (#50935) * Price filter: fix range slider update * Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce * Fix linting error * Remove unneeded state setter * Update plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts Co-authored-by: Alexandre Lara * Fix linting error --------- Co-authored-by: github-actions Co-authored-by: Alexandre Lara --- .../inner-blocks/price-filter/frontend.ts | 119 ++++++++++++++++-- .../inner-blocks/price-filter/types.ts | 1 + .../changelog/50935-fix-price-filter-slider | 4 + .../Blocks/BlockTypes/ProductFilterPrice.php | 2 + 4 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 plugins/woocommerce/changelog/50935-fix-price-filter-slider diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts index e715c219e71..482e3e51117 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts @@ -76,20 +76,88 @@ const debounceUpdate = debounce( ( context, element, event ) => { ); }, 1000 ); +const constrainRangeSliderValues = ( + /** + * Tuple containing min and max values. + */ + values: [ number, number ], + /** + * Min allowed value for the sliders. + */ + min?: number | null, + /** + * Max allowed value for the sliders. + */ + max?: number | null, + /** + * Step value for the sliders. + */ + step = 1, + /** + * Whether we're currently interacting with the min range slider or not, so we update the correct values. + */ + isMin = false +): { minPrice: number; maxPrice: number } => { + let [ minValue, maxValue ] = values; + + const isFinite = ( n: number | null | undefined ): n is number => + Number.isFinite( n ); + + if ( ! isFinite( minValue ) ) { + minValue = min || 0; + } + + if ( ! isFinite( maxValue ) ) { + maxValue = max || step; + } + + if ( isFinite( min ) && min > minValue ) { + minValue = min; + } + + if ( isFinite( max ) && max <= minValue ) { + minValue = max - step; + } + + if ( isFinite( min ) && min >= maxValue ) { + maxValue = min + step; + } + + if ( isFinite( max ) && max < maxValue ) { + maxValue = max; + } + + if ( ! isMin && minValue >= maxValue ) { + minValue = maxValue - step; + } + + if ( isMin && maxValue <= minValue ) { + maxValue = minValue + step; + } + + return { minPrice: minValue, maxPrice: maxValue }; +}; + +const getRangeStyle = ( + minPrice: number, + maxPrice: number, + minRange: number, + maxRange: number +) => { + return `--low: ${ + ( 100 * ( minPrice - minRange ) ) / ( maxRange - minRange ) + }%; --high: ${ + ( 100 * ( maxPrice - minRange ) ) / ( maxRange - minRange ) + }%;`; +}; + store< PriceFilterStore >( 'woocommerce/product-filter-price', { state: { rangeStyle: () => { const { minPrice, maxPrice, minRange, maxRange } = getContext< PriceFilterContext >(); - return [ - `--low: ${ - ( 100 * ( minPrice - minRange ) ) / ( maxRange - minRange ) - }%`, - `--high: ${ - ( 100 * ( maxPrice - minRange ) ) / ( maxRange - minRange ) - }%`, - ].join( ';' ); + return getRangeStyle( minPrice, maxPrice, minRange, maxRange ); }, formattedMinPrice: () => { const { minPrice } = getContext< PriceFilterContext >(); @@ -126,5 +194,40 @@ store< PriceFilterStore >( 'woocommerce/product-filter-price', { } ) ); }, + updateRange: ( event: HTMLElementEvent< HTMLInputElement > ) => { + const context = getContext< PriceFilterContext >(); + const { minPrice, maxPrice, minRange, maxRange } = context; + const isMin = event.target.classList.contains( 'min' ); + const targetValue = Number( event.target.value ); + const stepValue = 1; + const currentValues: [ number, number ] = isMin + ? [ + Math.round( targetValue / stepValue ) * stepValue, + maxPrice, + ] + : [ + minPrice, + Math.round( targetValue / stepValue ) * stepValue, + ]; + const values = constrainRangeSliderValues( + currentValues, + minRange, + maxRange, + stepValue, + isMin + ); + + if ( targetValue >= maxPrice ) { + context.maxPrice = minPrice + 1; + } else if ( targetValue <= minPrice ) { + context.minPrice = maxPrice - 1; + } + + if ( isMin ) { + context.minPrice = values.minPrice; + } else { + context.maxPrice = values.maxPrice; + } + }, }, } ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/types.ts index ed89d32a8e2..c08e024e8c5 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/types.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/types.ts @@ -34,5 +34,6 @@ export type PriceFilterStore = { updateProducts: ( event: HTMLElementEvent< HTMLInputElement > ) => void; selectInputContent: () => void; reset: () => void; + updateRange: ( event: HTMLElementEvent< HTMLInputElement > ) => void; }; }; diff --git a/plugins/woocommerce/changelog/50935-fix-price-filter-slider b/plugins/woocommerce/changelog/50935-fix-price-filter-slider new file mode 100644 index 00000000000..b8d0d2b926b --- /dev/null +++ b/plugins/woocommerce/changelog/50935-fix-price-filter-slider @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak +Comment: Price slider: fix range bar styling and dynamic input + diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php index 838adae31b3..97b73763b65 100644 --- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php +++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php @@ -234,6 +234,7 @@ final class ProductFilterPrice extends AbstractBlock { data-wc-bind--max="context.maxRange" data-wc-bind--value="context.minPrice" data-wc-on--change="actions.updateProducts" + data-wc-on--input="actions.updateRange" >
        From c63bb88e0edab9f56aa63dce1236ea0ae5e14274 Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Tue, 27 Aug 2024 14:30:01 +0800 Subject: [PATCH 111/185] Add react-powered main payments settings screen (#50825) * Fix payment store selector type * Add changelog * Add react-powered payment settings main screen * Add changelog * Update style * Revert changes * Fix enable payment gateway error * Fix wcpay install busy state * Check if Nonce exist or not * Fix extra payment methods * Fix untranslated texts * Fix lint --- .../add-react-main-payments-settings-screen | 4 + .../js/data/src/payment-gateways/index.ts | 4 +- .../components/other-payment-methods.tsx | 155 +++++++++++++++ .../components/payment-method.tsx | 183 ++++++++++++++++++ .../components/wcpay-install-button.tsx | 60 ++++++ .../settings-payments-main.scss | 32 ++- .../settings-payments-main.tsx | 95 ++++++++- .../client/typings/global.d.ts | 6 + .../add-react-main-payments-settings-screen | 4 + ...ass-wc-settings-payment-gateways-react.php | 15 ++ 10 files changed, 548 insertions(+), 10 deletions(-) create mode 100644 packages/js/data/changelog/add-react-main-payments-settings-screen create mode 100644 plugins/woocommerce-admin/client/settings-payments/components/other-payment-methods.tsx create mode 100644 plugins/woocommerce-admin/client/settings-payments/components/payment-method.tsx create mode 100644 plugins/woocommerce-admin/client/settings-payments/components/wcpay-install-button.tsx create mode 100644 plugins/woocommerce/changelog/add-react-main-payments-settings-screen diff --git a/packages/js/data/changelog/add-react-main-payments-settings-screen b/packages/js/data/changelog/add-react-main-payments-settings-screen new file mode 100644 index 00000000000..0aa0b00a417 --- /dev/null +++ b/packages/js/data/changelog/add-react-main-payments-settings-screen @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix payment store selector type diff --git a/packages/js/data/src/payment-gateways/index.ts b/packages/js/data/src/payment-gateways/index.ts index b9c74e18f19..afd3e78c926 100644 --- a/packages/js/data/src/payment-gateways/index.ts +++ b/packages/js/data/src/payment-gateways/index.ts @@ -13,7 +13,7 @@ import * as resolvers from './resolvers'; import * as selectors from './selectors'; import reducer from './reducer'; import { STORE_KEY } from './constants'; -import { WPDataActions } from '../types'; +import { WPDataSelectors } from '../types'; import { PromiseifySelectors } from '../types/promiseify-selectors'; export const PAYMENT_GATEWAYS_STORE_NAME = STORE_KEY; @@ -33,7 +33,7 @@ declare module '@wordpress/data' { ): DispatchFromMap< typeof actions >; function select( key: typeof STORE_KEY - ): SelectFromMap< typeof selectors > & WPDataActions; + ): SelectFromMap< typeof selectors > & WPDataSelectors; function resolveSelect( key: typeof STORE_KEY ): PromiseifySelectors< SelectFromMap< typeof selectors > >; diff --git a/plugins/woocommerce-admin/client/settings-payments/components/other-payment-methods.tsx b/plugins/woocommerce-admin/client/settings-payments/components/other-payment-methods.tsx new file mode 100644 index 00000000000..49228cb4276 --- /dev/null +++ b/plugins/woocommerce-admin/client/settings-payments/components/other-payment-methods.tsx @@ -0,0 +1,155 @@ +/** + * External dependencies + */ +import React, { useMemo } from '@wordpress/element'; +import { Button } from '@wordpress/components'; +import ExternalIcon from 'gridicons/dist/external'; +import { __, _x } from '@wordpress/i18n'; +import { + ONBOARDING_STORE_NAME, + PAYMENT_GATEWAYS_STORE_NAME, + SETTINGS_STORE_NAME, +} from '@woocommerce/data'; +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { getCountryCode } from '~/dashboard/utils'; +import { + getEnrichedPaymentGateways, + getIsGatewayWCPay, + getIsWCPayOrOtherCategoryDoneSetup, + getSplitGateways, +} from '~/task-lists/fills/PaymentGatewaySuggestions/utils'; + +type PaymentGateway = { + id: string; + image_72x72: string; + title: string; + enabled: boolean; + needsSetup: boolean; + // Add other properties as needed... +}; + +const usePaymentGatewayData = () => { + return useSelect( ( select ) => { + const { getSettings } = select( SETTINGS_STORE_NAME ); + const { general: settings = {} } = getSettings( 'general' ); + return { + getPaymentGateway: select( PAYMENT_GATEWAYS_STORE_NAME ) + .getPaymentGateway, + installedPaymentGateways: select( + PAYMENT_GATEWAYS_STORE_NAME + ).getPaymentGateways(), + isResolving: select( ONBOARDING_STORE_NAME ).isResolving( + 'getPaymentGatewaySuggestions' + ), + paymentGatewaySuggestions: select( + ONBOARDING_STORE_NAME + ).getPaymentGatewaySuggestions(), + countryCode: getCountryCode( settings.woocommerce_default_country ), + }; + }, [] ); +}; + +const AdditionalGatewayImages = ( { + additionalGateways, +}: { + additionalGateways: PaymentGateway[]; +} ) => ( + <> + { additionalGateways.map( ( gateway ) => ( + { + ) ) } + { _x( '& more.', 'More payment providers to discover', 'woocommerce' ) } + +); + +export const OtherPaymentMethods = () => { + const { + paymentGatewaySuggestions, + installedPaymentGateways, + isResolving, + countryCode, + } = usePaymentGatewayData(); + + const paymentGateways = useMemo( + () => + getEnrichedPaymentGateways( + installedPaymentGateways, + paymentGatewaySuggestions + ), + [ installedPaymentGateways, paymentGatewaySuggestions ] + ); + + const isWCPayOrOtherCategoryDoneSetup = useMemo( + () => + getIsWCPayOrOtherCategoryDoneSetup( paymentGateways, countryCode ), + [ countryCode, paymentGateways ] + ); + + const isWCPaySupported = Array.from( paymentGateways.values() ).some( + getIsGatewayWCPay + ); + + // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars + const [ wcPayGateway, _offlineGateways, additionalGateways ] = useMemo( + () => + getSplitGateways( + paymentGateways, + countryCode ?? '', + isWCPaySupported, + isWCPayOrOtherCategoryDoneSetup + ), + [ + paymentGateways, + countryCode, + isWCPaySupported, + isWCPayOrOtherCategoryDoneSetup, + ] + ); + + if ( isResolving || ! wcPayGateway ) { + return null; + } + + const hasWcPaySetup = wcPayGateway.enabled && ! wcPayGateway.needsSetup; + + return ( + <> + + { additionalGateways.length > 0 && ( + + ) } + + ); +}; diff --git a/plugins/woocommerce-admin/client/settings-payments/components/payment-method.tsx b/plugins/woocommerce-admin/client/settings-payments/components/payment-method.tsx new file mode 100644 index 00000000000..fa7adf07c28 --- /dev/null +++ b/plugins/woocommerce-admin/client/settings-payments/components/payment-method.tsx @@ -0,0 +1,183 @@ +/** + * External dependencies + */ +import { useState } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; +import { PaymentGateway } from '@woocommerce/data'; +import { WooPaymentMethodsLogos } from '@woocommerce/onboarding'; + +/** + * Internal dependencies + */ +import { getAdminSetting } from '~/utils/admin-settings'; +import sanitizeHTML from '~/lib/sanitize-html'; +import { WCPayInstallButton } from './wcpay-install-button'; + +export const PaymentMethod = ( { + id, + enabled, + title, + method_title, + method_description, + settings_url, +}: PaymentGateway ) => { + const isWooPayEligible = getAdminSetting( 'isWooPayEligible', false ); + const [ isEnabled, setIsEnabled ] = useState( enabled ); + const [ isLoading, setIsLoading ] = useState( false ); + + const toggleEnabled = async ( e: React.MouseEvent ) => { + e.preventDefault(); + setIsLoading( true ); + + if ( ! window.woocommerce_admin.nonces?.gateway_toggle ) { + // eslint-disable-next-line no-console + console.warn( 'Unexpected error: Nonce not found' ); + // Redirect to payment setting page if nonce is not found. Users should still be able to toggle the payment method from that page. + window.location.href = settings_url; + return; + } + + try { + const response = await fetch( window.woocommerce_admin.ajax_url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams( { + action: 'woocommerce_toggle_gateway_enabled', + security: window.woocommerce_admin.nonces?.gateway_toggle, + gateway_id: id, + } ), + } ); + + const result = await response.json(); + + if ( result.success ) { + if ( result.data === true ) { + setIsEnabled( true ); + } else if ( result.data === false ) { + setIsEnabled( false ); + } else if ( result.data === 'needs_setup' ) { + window.location.href = settings_url; + } + } else { + window.location.href = settings_url; + } + } catch ( error ) { + // eslint-disable-next-line no-console + console.error( 'Error toggling gateway:', error ); + } finally { + setIsLoading( false ); + } + }; + + return ( + + + +
        + + { method_title } + + { id !== 'pre_install_woocommerce_payments_promotion' && + method_title !== title && ( + +  –  + { title } + + ) } + { id === 'pre_install_woocommerce_payments_promotion' && ( +
        + +
        + ) } +
        + + + + + { isEnabled + ? __( 'Yes', 'woocommerce' ) + : __( 'No', 'woocommerce' ) } + + + + + + { id === 'pre_install_woocommerce_payments_promotion' ? ( + + ) : ( + + { enabled + ? __( 'Manage', 'woocommerce' ) + : __( 'Finish setup', 'woocommerce' ) } + + ) } + + + ); +}; diff --git a/plugins/woocommerce-admin/client/settings-payments/components/wcpay-install-button.tsx b/plugins/woocommerce-admin/client/settings-payments/components/wcpay-install-button.tsx new file mode 100644 index 00000000000..a5583bd73f6 --- /dev/null +++ b/plugins/woocommerce-admin/client/settings-payments/components/wcpay-install-button.tsx @@ -0,0 +1,60 @@ +/** + * External dependencies + */ +import React, { useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { + PAYMENT_GATEWAYS_STORE_NAME, + PLUGINS_STORE_NAME, +} from '@woocommerce/data'; +import { Button } from '@wordpress/components'; +import { resolveSelect, useDispatch } from '@wordpress/data'; +import { recordEvent } from '@woocommerce/tracks'; + +const slug = 'woocommerce-payments'; +export const WCPayInstallButton = () => { + const [ installing, setInstalling ] = useState( false ); + const { installAndActivatePlugins } = useDispatch( PLUGINS_STORE_NAME ); + const { createNotice } = useDispatch( 'core/notices' ); + + const redirectToSettings = async () => { + const paymentGateway = await resolveSelect( + PAYMENT_GATEWAYS_STORE_NAME + ).getPaymentGateway( slug.replace( /-/g, '_' ) ); + + if ( paymentGateway?.settings_url ) { + window.location.href = paymentGateway.settings_url; + } + }; + + const installWooCommercePayments = async () => { + if ( installing ) return; + + setInstalling( true ); + recordEvent( 'settings_payments_recommendations_setup', { + extension_selected: slug, + } ); + + try { + await installAndActivatePlugins( [ slug ] ); + redirectToSettings(); + } catch ( error ) { + if ( error instanceof Error ) { + createNotice( 'error', error.message ); + } + setInstalling( false ); + } + }; + + return ( + + ); +}; diff --git a/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.scss b/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.scss index a63d140104c..64beb4baac8 100644 --- a/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.scss +++ b/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.scss @@ -1,9 +1,29 @@ +@import "~/wp-admin-scripts/payment-method-promotions/payment-promotion-row.scss"; + .settings-payments-main__container { - h1 { - color: #fff; + .settings-payments-main__spinner { + display: flex; + justify-content: center; + align-items: center; + position: absolute; + width: 100%; + } + + + table.wc_gateways { + .other-payment-methods__button-text { + margin-right: 4px; + } + + td.other-payment-methods-row { + border-top: 1px solid #c3c4c7; + background-color: #fff; + + } + + .other-payment-methods__image { + vertical-align: middle; + margin-right: 8px; + } } - background: #000; - text-align: center; - padding: 50px 0; - width: 100%; } diff --git a/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.tsx b/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.tsx index c2671e205bf..94f85355931 100644 --- a/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.tsx +++ b/plugins/woocommerce-admin/client/settings-payments/settings-payments-main.tsx @@ -1,17 +1,108 @@ /** * External dependencies */ -import '@wordpress/element'; +import { useMemo } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { PaymentGateway } from '@woocommerce/data'; /** * Internal dependencies */ import './settings-payments-main.scss'; +import { PaymentMethod } from './components/payment-method'; +import { OtherPaymentMethods } from './components/other-payment-methods'; +import { PaymentsBannerWrapper } from '~/payments/payment-settings-banner'; export const SettingsPaymentsMain: React.FC = () => { + const [ paymentGateways, error ] = useMemo( () => { + const script = document.getElementById( + 'experimental_wc_settings_payments_gateways' + ); + + try { + if ( script && script.textContent ) { + return [ + JSON.parse( script.textContent ) as PaymentGateway[], + null, + ]; + } + throw new Error( 'Could not find payment gateways data' ); + } catch ( e ) { + return [ [], e as Error ]; + } + }, [] ); + + if ( error ) { + // This is a temporary error message to be replaced by error boundary. + return ( +
        +

        + { __( 'Error loading payment gateways', 'woocommerce' ) } +

        +

        { error.message }

        +
        + ); + } + return (
        -

        Main payments screen

        +
        + +
        + + + + + + +
        + + + + + + + + + + + + { paymentGateways.map( + ( gateway: PaymentGateway ) => ( + + ) + ) } + + + + + +
        + { __( 'Method', 'woocommerce' ) } + + { __( 'Enabled', 'woocommerce' ) } + + { __( + 'Description', + 'woocommerce' + ) } +
        + +
        +
        ); }; diff --git a/plugins/woocommerce-admin/client/typings/global.d.ts b/plugins/woocommerce-admin/client/typings/global.d.ts index 7e0aeebf77c..9c3a8c79e4b 100644 --- a/plugins/woocommerce-admin/client/typings/global.d.ts +++ b/plugins/woocommerce-admin/client/typings/global.d.ts @@ -88,6 +88,12 @@ declare global { getUserSetting?: ( name: string ) => string | undefined; setUserSetting?: ( name: string, value: string ) => void; deleteUserSetting?: ( name: string ) => void; + woocommerce_admin: { + ajax_url: string; + nonces: { + gateway_toggle?: string; + } + } } } diff --git a/plugins/woocommerce/changelog/add-react-main-payments-settings-screen b/plugins/woocommerce/changelog/add-react-main-payments-settings-screen new file mode 100644 index 00000000000..d92bea60fbb --- /dev/null +++ b/plugins/woocommerce/changelog/add-react-main-payments-settings-screen @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add react-powered main payments settings screen diff --git a/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php b/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php index 178c33a4daf..88ee03acd20 100644 --- a/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php +++ b/plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways-react.php @@ -57,6 +57,16 @@ class WC_Settings_Payment_Gateways_React extends WC_Settings_Page { //phpcs:disable WordPress.Security.NonceVerification.Recommended global $current_section; + // We don't want to output anything from the action for now. So we buffer it and discard it. + ob_start(); + /** + * Fires before the payment gateways settings fields are rendered. + * + * @since 1.5.7 + */ + do_action( 'woocommerce_admin_field_payment_gateways' ); + ob_end_clean(); + // Load gateways so we can show any global options they may have. $payment_gateways = WC()->payment_gateways->payment_gateways(); @@ -91,6 +101,11 @@ class WC_Settings_Payment_Gateways_React extends WC_Settings_Page { global $hide_save_button; $hide_save_button = true; echo '
        '; + + // Output the gateways data to the page so the React app can use it. + $controller = new WC_REST_Payment_Gateways_Controller(); + $response = $controller->get_items( new WP_REST_Request( 'GET', '/wc/v3/payment_gateways' ) ); + echo ''; } /** From 5a80d5e1dae4e011e16611a3dfcb7d820dcdd7ca Mon Sep 17 00:00:00 2001 From: Karol Manijak <20098064+kmanijak@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:04:15 +0200 Subject: [PATCH 112/185] Update Block Reference and make it public doc (#50906) * Update Block References doc * Move the Block References to public Docs * Change the place Block Reference is generated to * Add changelog * Update docs manifest file * Update manifest --- .../building-a-woo-store}/block-references.md | 73 +++++++++++++------ docs/docs-manifest.json | 12 ++- .../bin/gen-block-list-doc.js | 13 +++- .../changelog/update-block-reference | 4 + 4 files changed, 74 insertions(+), 28 deletions(-) rename {plugins/woocommerce-blocks/docs/block-references => docs/building-a-woo-store}/block-references.md (95%) create mode 100644 plugins/woocommerce/changelog/update-block-reference diff --git a/plugins/woocommerce-blocks/docs/block-references/block-references.md b/docs/building-a-woo-store/block-references.md similarity index 95% rename from plugins/woocommerce-blocks/docs/block-references/block-references.md rename to docs/building-a-woo-store/block-references.md index 3e3f4d1c3db..7790efb5eb7 100644 --- a/plugins/woocommerce-blocks/docs/block-references/block-references.md +++ b/docs/building-a-woo-store/block-references.md @@ -1,9 +1,25 @@ +--- +post_title: Blocks reference +menu_title: Blocks Reference +--- + # Woo Blocks Reference This page lists the Woo blocks included in the package. (Incomplete as there are still blocks that are not using block.json definition). +## Add to Cart with Options - woocommerce/add-to-cart-form + +Display a button so the customer can add a product to their cart. Options will also be displayed depending on product type. e.g. quantity, variation. + +- **Name:** woocommerce/add-to-cart-form +- **Category:** woocommerce-product-elements +- **Ancestor:** +- **Parent:** +- **Supports:** +- **Attributes:** isDescendentOfSingleProductBlock + ## Product Average Rating (Beta) - woocommerce/product-average-rating Display the average rating of a product @@ -650,7 +666,7 @@ Renders classic WooCommerce shortcodes. - **Category:** woocommerce - **Ancestor:** - **Parent:** -- **Supports:** color (text, ~~background~~) +- **Supports:** color (text, ~~background~~), ~~inserter~~ - **Attributes:** color, storeOnly ## Customer account - woocommerce/customer-account @@ -717,7 +733,7 @@ Display a button for shoppers to quickly view their cart. - **Ancestor:** - **Parent:** - **Supports:** typography (fontSize), ~~html~~, ~~multiple~~ -- **Attributes:** addToCartBehaviour, cartAndCheckoutRenderStyle, hasHiddenPrice, iconColor, iconColorValue, isPreview, miniCartIcon, priceColor, priceColorValue, productCountColor, productCountColorValue +- **Attributes:** addToCartBehaviour, cartAndCheckoutRenderStyle, hasHiddenPrice, iconColor, iconColorValue, isPreview, miniCartIcon, priceColor, priceColorValue, productCountColor, productCountColorValue, productCountVisibility ## Empty Mini-Cart view - woocommerce/empty-mini-cart-contents-block @@ -1060,29 +1076,18 @@ The contents of this block will display when there are no products found. - **Supports:** align, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ - **Attributes:** -## Add to Cart with Options - woocommerce/add-to-cart-form - -Display a button so the customer can add a product to their cart. Options will also be displayed depending on product type. e.g. quantity, variation. - -- **Name:** woocommerce/add-to-cart-form -- **Category:** woocommerce-product-elements -- **Ancestor:** -- **Parent:** -- **Supports:** interactivity -- **Attributes:** isDescendentOfSingleProductBlock, quantitySelectorStyle - ## Product Filter (Experimental) - woocommerce/product-filter A block that adds product filters to the product collection. - **Name:** woocommerce/product-filter - **Category:** woocommerce -- **Ancestor:** +- **Ancestor:** woocommerce/product-filters - **Parent:** - **Supports:** ~~html~~, ~~inserter~~, ~~reusable~~ - **Attributes:** attributeId, filterType, heading, isPreview -## Product Filter: Active Filters (Experimental) - woocommerce/product-filter-active +## Filter Options - woocommerce/product-filter-active Display the currently active filters. @@ -1093,7 +1098,7 @@ Display the currently active filters. - **Supports:** color (text, ~~background~~), interactivity, ~~inserter~~ - **Attributes:** displayStyle -## Product Filter: Attribute (Experimental) - woocommerce/product-filter-attribute +## Filter Options - woocommerce/product-filter-attribute Enable customers to filter the product grid by selecting one or more attributes, such as color. @@ -1101,8 +1106,8 @@ Enable customers to filter the product grid by selecting one or more attributes, - **Category:** woocommerce - **Ancestor:** woocommerce/product-filter - **Parent:** -- **Supports:** color (text, ~~background~~), interactivity, ~~inserter~~ -- **Attributes:** attributeId, displayStyle, isPreview, queryType, selectType, showCounts +- **Supports:** color (text, ~~background~~), interactivity, spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~inserter~~ +- **Attributes:** attributeId, clearButton, displayStyle, hideEmpty, isPreview, queryType, selectType, showCounts, sortOrder ## Clear (Experimental) - woocommerce/product-filter-clear-button @@ -1115,7 +1120,7 @@ Allows shoppers to reset this filter. - **Supports:** interactivity, ~~inserter~~ - **Attributes:** -## Product Filter: Price (Experimental) - woocommerce/product-filter-price +## Filter Options - woocommerce/product-filter-price Enable customers to filter the product collection by choosing a price range. @@ -1126,7 +1131,7 @@ Enable customers to filter the product collection by choosing a price range. - **Supports:** interactivity, ~~inserter~~ - **Attributes:** inlineInput, showInputFields -## Product Filter: Rating (Experimental) - woocommerce/product-filter-rating +## Filter Options - woocommerce/product-filter-rating Enable customers to filter the product collection by rating. @@ -1137,7 +1142,7 @@ Enable customers to filter the product collection by rating. - **Supports:** color (text, ~~background~~), interactivity, ~~inserter~~ - **Attributes:** className, displayStyle, isPreview, selectType, showCounts -## Product Filter: Stock Status (Experimental) - woocommerce/product-filter-stock-status +## Filter Options - woocommerce/product-filter-stock-status Enable customers to filter the product collection by stock status. @@ -1156,8 +1161,30 @@ Let shoppers filter products displayed on the page. - **Category:** woocommerce - **Ancestor:** - **Parent:** -- **Supports:** align, interactivity, ~~multiple~~ -- **Attributes:** +- **Supports:** align, color (background, text), interactivity, layout (allowJustification, allowOrientation, allowVerticalAlignment, default, ~~allowInheriting~~), spacing (blockGap), typography (fontSize, textAlign), ~~inserter~~, ~~multiple~~ +- **Attributes:** overlay, overlayButtonStyle, overlayIcon, overlayIconSize + +## Product Filters Overlay (Experimental) - woocommerce/product-filters-overlay + +Display product filters in an overlay on top of a page. + +- **Name:** woocommerce/product-filters-overlay +- **Category:** woocommerce +- **Ancestor:** +- **Parent:** +- **Supports:** align, color (background, text), dimensions (), layout (allowCustomContentAndWideSize), spacing (blockGap, padding), typography (), ~~inserter~~, ~~multiple~~ +- **Attributes:** overlayPosition, overlayStyle, style + +## Overlay Navigation (Experimental) - woocommerce/product-filters-overlay-navigation + +Display overlay navigation controls. + +- **Name:** woocommerce/product-filters-overlay-navigation +- **Category:** woocommerce +- **Ancestor:** woocommerce/product-filters-overlay,woocommerce/product-filters +- **Parent:** +- **Supports:** align (center, left, right), color (background, text), layout (default, ~~allowEditing~~), position (sticky), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~inserter~~ +- **Attributes:** align, buttonStyle, iconSize, navigationStyle, overlayMode, style, triggerType ## Product Gallery (Beta) - woocommerce/product-gallery diff --git a/docs/docs-manifest.json b/docs/docs-manifest.json index e6096fbec57..71657d789c4 100644 --- a/docs/docs-manifest.json +++ b/docs/docs-manifest.json @@ -70,6 +70,14 @@ "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/building-a-woo-store/configuring-caching-plugins.md", "id": "9f484f8db1111fa6c1b6108d40939c967eea7f47" }, + { + "post_title": "Blocks reference", + "menu_title": "Blocks Reference", + "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/building-a-woo-store/block-references.md", + "hash": "b6cd78cba78be8846621f27b9d4a408c713e1915bdbb7fc27b6247b3ff8610f1", + "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/building-a-woo-store/block-references.md", + "id": "1fbe91d7fa4fafaf35f0297e4cee1e7958756aed" + }, { "post_title": "How to add a custom field to simple and variable products", "menu_title": "Add Custom Fields to Products", @@ -1302,7 +1310,7 @@ "post_title": "How to request WooCommerce extension reviews", "menu_title": "Requesting reviews", "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md", - "hash": "5a77783c32c1bb0fefc6888f7a3217fe6e5c7242692593a17828b2f1ffec618b", + "hash": "dfdf5add075777636eb628d25484e93268251437dec0253766c12d80ac82573b", "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/review-guidelines/how-to-request-reviews.md", "id": "3d0c8bf7339a71198737d19eec7e6d71697b3727" } @@ -1796,5 +1804,5 @@ "categories": [] } ], - "hash": "7e929e4f5594921717bb3407ea502c4a01d4dabee6b8b1d441cd14fda4b22248" + "hash": "e054beda95d791f118b8aba90fd63fe1c28ce9f008d89fd863397aac7bf9e827" } \ No newline at end of file diff --git a/plugins/woocommerce-blocks/bin/gen-block-list-doc.js b/plugins/woocommerce-blocks/bin/gen-block-list-doc.js index e46aa289525..bc1a178e2fd 100644 --- a/plugins/woocommerce-blocks/bin/gen-block-list-doc.js +++ b/plugins/woocommerce-blocks/bin/gen-block-list-doc.js @@ -17,14 +17,21 @@ const fs = require( 'fs' ); * * @type {string} */ -const ROOT_DIR = path.resolve( __dirname, '../' ); +const ROOT_DIR = path.resolve( __dirname, '../../../' ); + +/** + * Path to root Blocks project directory. + * + * @type {string} + */ +const BLOCK_LIBRARY_ROOT_DIR = path.resolve( __dirname, '../' ); /** * Path to blocks directory. * * @type {string} */ -const BLOCK_LIBRARY_DIR = path.resolve( ROOT_DIR, 'assets/js' ); +const BLOCK_LIBRARY_DIR = path.resolve( BLOCK_LIBRARY_ROOT_DIR, 'assets/js' ); /** * Path to docs file. @@ -33,7 +40,7 @@ const BLOCK_LIBRARY_DIR = path.resolve( ROOT_DIR, 'assets/js' ); */ const BLOCK_LIBRARY_DOCS_FILE = path.resolve( ROOT_DIR, - 'docs/block-references/block-references.md' + 'docs/building-a-woo-store/block-references.md' ); /** diff --git a/plugins/woocommerce/changelog/update-block-reference b/plugins/woocommerce/changelog/update-block-reference new file mode 100644 index 00000000000..64c0a52aa7f --- /dev/null +++ b/plugins/woocommerce/changelog/update-block-reference @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Make Block Reference a public doc From 47ff627048f8fc4506c81ad41e99b2fed7b08035 Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Tue, 27 Aug 2024 16:59:01 +0800 Subject: [PATCH 113/185] Fix site visibility badge style (#50976) * Fix site visibility badge style * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions --- .../changelog/50976-fix-coming-soon-badge | 4 ++++ .../ComingSoon/ComingSoonAdminBarBadge.php | 22 ++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 plugins/woocommerce/changelog/50976-fix-coming-soon-badge diff --git a/plugins/woocommerce/changelog/50976-fix-coming-soon-badge b/plugins/woocommerce/changelog/50976-fix-coming-soon-badge new file mode 100644 index 00000000000..dd7a9b78a5a --- /dev/null +++ b/plugins/woocommerce/changelog/50976-fix-coming-soon-badge @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix site visibility badge style \ No newline at end of file diff --git a/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php b/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php index 8a4c185fb8e..0b65041e322 100644 --- a/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php +++ b/plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php @@ -62,14 +62,26 @@ class ComingSoonAdminBarBadge { public function output_css() { if ( is_admin_bar_showing() ) { echo ' \ No newline at end of file diff --git a/plugins/woocommerce/changelog/add-stripe-tax-onboarding-tax-task b/plugins/woocommerce/changelog/add-stripe-tax-onboarding-tax-task new file mode 100644 index 00000000000..7de97421d64 --- /dev/null +++ b/plugins/woocommerce/changelog/add-stripe-tax-onboarding-tax-task @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Added Stripe tax in onboarding tax task diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php index ee8f9ce99be..ba33d9b2362 100644 --- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php +++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php @@ -129,9 +129,11 @@ class Tax extends Task { return array( 'avalara_activated' => PluginsHelper::is_plugin_active( 'woocommerce-avatax' ), 'tax_jar_activated' => class_exists( 'WC_Taxjar' ), + 'stripe_tax_activated' => PluginsHelper::is_plugin_active( 'stripe-tax-for-woocommerce' ), 'woocommerce_tax_activated' => PluginsHelper::is_plugin_active( 'woocommerce-tax' ), 'woocommerce_shipping_activated' => PluginsHelper::is_plugin_active( 'woocommerce-shipping' ), 'woocommerce_tax_countries' => self::get_automated_support_countries(), + 'stripe_tax_countries' => self::get_stripe_tax_support_countries(), ); } @@ -162,4 +164,54 @@ class Tax extends Task { return $tax_supported_countries; } + + /** + * Get an array of countries that support Stripe tax. + * + * @return array + */ + private static function get_stripe_tax_support_countries() { + // https://docs.stripe.com/tax/supported-countries#supported-countries accurate as of 2024-08-26. + // countries with remote sales not included. + return array( + 'AU', + 'AT', + 'BE', + 'BG', + 'CA', + 'HR', + 'CY', + 'CZ', + 'DK', + 'EE', + 'FI', + 'FR', + 'DE', + 'GR', + 'HK', + 'HU', + 'IE', + 'IT', + 'JP', + 'LV', + 'LT', + 'LU', + 'MT', + 'NL', + 'NZ', + 'NO', + 'PL', + 'PT', + 'RO', + 'SG', + 'SK', + 'SI', + 'ES', + 'SE', + 'CH', + 'AE', + 'GB', + 'US', + ); + } } From 84e689d8a493dd6b9821cc23ecd6a411d0d646ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 19:10:24 +0700 Subject: [PATCH 154/185] Delete changelog files based on PR 50923 (#51036) Delete changelog files for 50923 Co-authored-by: WooCommerce Bot --- .../changelog/50923-fix-remove-non-existing-method | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 plugins/woocommerce/changelog/50923-fix-remove-non-existing-method diff --git a/plugins/woocommerce/changelog/50923-fix-remove-non-existing-method b/plugins/woocommerce/changelog/50923-fix-remove-non-existing-method deleted file mode 100644 index c87d77f7127..00000000000 --- a/plugins/woocommerce/changelog/50923-fix-remove-non-existing-method +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: fix - -CYS - Remove usage of `prepare_item_for_response` function in `Images` endpoint. \ No newline at end of file From cd638721f9e133b2cf2f15ebb22157441a14127b Mon Sep 17 00:00:00 2001 From: Tung Du Date: Thu, 29 Aug 2024 22:23:40 +0700 Subject: [PATCH 155/185] [Experimental] Update folder structure for new product filter blocks (#51029) --- .../inner-blocks/active-filters/block.json | 0 .../active-filters/components/inspector.tsx | 0 .../components/removable-list-item.tsx | 0 .../inner-blocks/active-filters/edit.tsx | 0 .../inner-blocks/active-filters/frontend.ts | 2 +- .../inner-blocks/active-filters/index.tsx | 0 .../inner-blocks/active-filters/style.scss | 0 .../inner-blocks/active-filters/types.ts | 0 .../inner-blocks/attribute-filter/block.json | 0 .../components/attribute-dropdown.tsx | 0 .../components/attribute-select-controls.tsx | 0 .../components/checkbox-list-editor.tsx | 0 .../attribute-filter/components/inspector.tsx | 0 .../components/placeholder.tsx | 0 .../attribute-filter/constants.ts | 0 .../inner-blocks/attribute-filter/edit.tsx | 0 .../inner-blocks/attribute-filter/frontend.ts | 2 +- .../inner-blocks/attribute-filter/index.tsx | 0 .../inner-blocks/attribute-filter/style.scss | 0 .../inner-blocks/attribute-filter/types.ts | 0 .../inner-blocks/attribute-filter/utils.ts | 0 .../inner-blocks/clear-button/block.json | 0 .../inner-blocks/clear-button/edit.tsx | 0 .../inner-blocks/clear-button/frontend.ts | 2 +- .../inner-blocks/clear-button/index.tsx | 0 .../inner-blocks/clear-button/save.tsx | 0 .../components/preview-dropdown/index.tsx | 0 .../overlay-navigation}/block-variations.tsx | 0 .../overlay-navigation}/block.json | 0 .../inner-blocks/overlay-navigation}/edit.tsx | 4 ++-- .../overlay-navigation}/editor.scss | 0 .../overlay-navigation}/index.tsx | 0 .../inspector-controls.tsx | 0 .../inner-blocks/overlay-navigation}/save.tsx | 0 .../overlay-navigation}/style.scss | 0 .../inner-blocks/overlay-navigation}/types.ts | 2 +- .../inner-blocks/overlay}/block.json | 0 .../inner-blocks/overlay}/edit.tsx | 0 .../inner-blocks/overlay}/icon.tsx | 0 .../inner-blocks/overlay}/index.tsx | 0 .../inner-blocks/overlay}/save.tsx | 0 .../inner-blocks/overlay}/settings.ts | 0 .../inner-blocks/overlay}/types.ts | 0 .../inner-blocks/price-filter/block.json | 0 .../price-filter/components/inspector.tsx | 0 .../price-filter/components/price-slider.tsx | 0 .../inner-blocks/price-filter/edit.tsx | 0 .../inner-blocks/price-filter/frontend.ts | 2 +- .../inner-blocks/price-filter/index.tsx | 0 .../inner-blocks/price-filter/style.scss | 0 .../inner-blocks/price-filter/types.ts | 0 .../inner-blocks/price-filter/utils.ts | 0 .../product-filter/block-variations.tsx | 0 .../inner-blocks}/product-filter/block.json | 0 .../product-filter/components/warning.tsx | 0 .../inner-blocks}/product-filter/constants.ts | 0 .../inner-blocks}/product-filter/edit.tsx | 0 .../inner-blocks}/product-filter/editor.scss | 0 .../inner-blocks}/product-filter/frontend.ts | 0 .../inner-blocks}/product-filter/index.tsx | 0 .../inner-blocks}/product-filter/save.tsx | 0 .../inner-blocks}/product-filter/types.ts | 0 .../inner-blocks}/product-filter/utils.ts | 0 .../inner-blocks/rating-filter/block.json | 0 .../rating-filter/components/inspector.tsx | 0 .../inner-blocks/rating-filter/edit.tsx | 0 .../inner-blocks/rating-filter/frontend.ts | 2 +- .../inner-blocks/rating-filter/index.tsx | 0 .../inner-blocks/rating-filter/preview.tsx | 0 .../inner-blocks/rating-filter/style.scss | 0 .../inner-blocks/rating-filter/types.ts | 0 .../inner-blocks/rating-filter/utils.ts | 0 .../inner-blocks/stock-filter/block.json | 0 .../stock-filter/components/inspector.tsx | 0 .../inner-blocks/stock-filter/edit.tsx | 0 .../inner-blocks/stock-filter/frontend.ts | 2 +- .../inner-blocks/stock-filter/index.tsx | 0 .../inner-blocks/stock-filter/preview.tsx | 0 .../inner-blocks/stock-filter/style.scss | 0 .../inner-blocks/stock-filter/types.ts | 0 .../woocommerce-blocks/bin/webpack-entries.js | 21 +++++++++++-------- .../update-product-filters-folder-structure | 5 +++++ 82 files changed, 26 insertions(+), 18 deletions(-) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/components/inspector.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/components/removable-list-item.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/frontend.ts (90%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/style.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/active-filters/types.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/components/attribute-dropdown.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/components/attribute-select-controls.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/components/checkbox-list-editor.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/components/inspector.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/components/placeholder.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/constants.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/frontend.ts (98%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/style.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/types.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/attribute-filter/utils.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/clear-button/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/clear-button/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/clear-button/frontend.ts (96%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/clear-button/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/clear-button/save.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/components/preview-dropdown/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/block-variations.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/edit.tsx (97%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/editor.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/inspector-controls.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/save.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/style.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay-navigation => product-filters/inner-blocks/overlay-navigation}/types.ts (96%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay => product-filters/inner-blocks/overlay}/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay => product-filters/inner-blocks/overlay}/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay => product-filters/inner-blocks/overlay}/icon.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay => product-filters/inner-blocks/overlay}/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay => product-filters/inner-blocks/overlay}/save.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay => product-filters/inner-blocks/overlay}/settings.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filters-overlay => product-filters/inner-blocks/overlay}/types.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/components/inspector.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/components/price-slider.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/frontend.ts (99%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/style.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/types.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/price-filter/utils.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/block-variations.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/components/warning.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/constants.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/editor.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/frontend.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/save.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/types.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{ => product-filters/inner-blocks}/product-filter/utils.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/components/inspector.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/frontend.ts (97%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/preview.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/style.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/types.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/rating-filter/utils.ts (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/block.json (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/components/inspector.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/edit.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/frontend.ts (98%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/index.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/preview.tsx (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/style.scss (100%) rename plugins/woocommerce-blocks/assets/js/blocks/{product-filter => product-filters}/inner-blocks/stock-filter/types.ts (100%) create mode 100644 plugins/woocommerce/changelog/update-product-filters-folder-structure diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/components/inspector.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/components/inspector.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/components/inspector.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/components/inspector.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/components/removable-list-item.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/components/removable-list-item.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/components/removable-list-item.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/components/removable-list-item.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/frontend.ts similarity index 90% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/frontend.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/frontend.ts index 69cab9093e1..0b462692f15 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/frontend.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/frontend.ts @@ -6,7 +6,7 @@ import { store, getContext } from '@woocommerce/interactivity'; /** * Internal dependencies */ -import { navigate } from '../../frontend'; +import { navigate } from '../product-filter/frontend'; type ActiveFiltersContext = { queryId: number; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/style.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/style.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/style.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/types.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/active-filters/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/types.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/attribute-dropdown.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/attribute-dropdown.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/attribute-dropdown.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/attribute-dropdown.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/attribute-select-controls.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/attribute-select-controls.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/attribute-select-controls.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/attribute-select-controls.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/checkbox-list-editor.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/checkbox-list-editor.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/checkbox-list-editor.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/checkbox-list-editor.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/inspector.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/inspector.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/inspector.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/inspector.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/placeholder.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/placeholder.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/components/placeholder.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/components/placeholder.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/constants.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/constants.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/constants.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/constants.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/frontend.ts similarity index 98% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/frontend.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/frontend.ts index 9c0300a8dd6..0f9eb935586 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/frontend.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/frontend.ts @@ -8,7 +8,7 @@ import { HTMLElementEvent } from '@woocommerce/types'; /** * Internal dependencies */ -import { navigate } from '../../frontend'; +import { navigate } from '../product-filter/frontend'; type AttributeFilterContext = { attributeSlug: string; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/style.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/style.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/style.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/types.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/types.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/utils.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/utils.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/attribute-filter/utils.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/utils.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/frontend.ts similarity index 96% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/frontend.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/frontend.ts index 7f1164ddf2d..0bfc299b660 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/frontend.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/frontend.ts @@ -6,7 +6,7 @@ import { store, getContext } from '@woocommerce/interactivity'; /** * Internal dependencies */ -import { navigate } from '../../frontend'; +import { navigate } from '../product-filter/frontend'; const getQueryParams = ( e: Event ) => { const filterNavContainer = ( e.target as HTMLElement )?.closest( diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/save.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/save.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/clear-button/save.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/clear-button/save.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/components/preview-dropdown/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/components/preview-dropdown/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/components/preview-dropdown/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/components/preview-dropdown/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/block-variations.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/block-variations.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/block-variations.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/block-variations.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/edit.tsx similarity index 97% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/edit.tsx index 58bec7471d0..43e026f95cf 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/edit.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/edit.tsx @@ -16,8 +16,8 @@ import type { BlockContext, BlockVariationTriggerType, } from './types'; -import { default as productFiltersIcon } from '../product-filters/icon'; -import { BlockOverlayAttribute as ProductFiltersBlockOverlayAttribute } from '../product-filters/constants'; +import { default as productFiltersIcon } from '../../icon'; +import { BlockOverlayAttribute as ProductFiltersBlockOverlayAttribute } from '../../constants'; import './editor.scss'; import { Inspector } from './inspector-controls'; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/editor.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/editor.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/editor.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/editor.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/inspector-controls.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/inspector-controls.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/inspector-controls.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/inspector-controls.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/save.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/save.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/save.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/save.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/style.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/style.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/style.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/types.ts similarity index 96% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/types.ts index 70d465198e2..e5694e1a323 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay-navigation/types.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay-navigation/types.ts @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { BlockOverlayAttributeOptions as ProductFiltersBlockOverlayAttributeOptions } from '../product-filters/types'; +import { BlockOverlayAttributeOptions as ProductFiltersBlockOverlayAttributeOptions } from '../../types'; type BorderRadius = { bottomLeft: string; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/icon.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/icon.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/icon.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/icon.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/save.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/save.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/save.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/save.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/settings.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/settings.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/settings.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/settings.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/types.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filters-overlay/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/overlay/types.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/components/inspector.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/components/inspector.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/components/inspector.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/components/inspector.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/components/price-slider.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/components/price-slider.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/components/price-slider.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/components/price-slider.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/frontend.ts similarity index 99% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/frontend.ts index 482e3e51117..844e3c364f6 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/frontend.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/frontend.ts @@ -9,7 +9,7 @@ import { debounce } from '@woocommerce/base-utils'; /** * Internal dependencies */ -import { navigate } from '../../frontend'; +import { navigate } from '../product-filter/frontend'; import type { PriceFilterContext, PriceFilterStore } from './types'; const getUrl = ( context: PriceFilterContext ) => { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/style.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/style.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/style.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/types.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/types.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/utils.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/utils.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/price-filter/utils.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/utils.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/block-variations.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/block-variations.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/block-variations.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/block-variations.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/components/warning.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/components/warning.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/components/warning.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/components/warning.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/constants.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/constants.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/constants.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/constants.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/editor.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/editor.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/editor.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/editor.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/frontend.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/frontend.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/frontend.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/save.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/save.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/save.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/save.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/types.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/types.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/utils.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/utils.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/utils.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/product-filter/utils.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/components/inspector.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/components/inspector.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/components/inspector.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/components/inspector.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/frontend.ts similarity index 97% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/frontend.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/frontend.ts index 8d865131b33..3bd9f961704 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/frontend.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/frontend.ts @@ -8,7 +8,7 @@ import { DropdownContext } from '@woocommerce/interactivity-components/dropdown' /** * Internal dependencies */ -import { navigate } from '../../frontend'; +import { navigate } from '../product-filter/frontend'; function getUrl( filters: Array< string | null > ) { filters = filters.filter( Boolean ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/preview.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/preview.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/preview.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/preview.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/style.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/style.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/style.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/types.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/types.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/utils.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/utils.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/rating-filter/utils.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/utils.ts diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/block.json b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/block.json similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/block.json rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/block.json diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/components/inspector.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/components/inspector.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/components/inspector.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/components/inspector.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/edit.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/edit.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/edit.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/frontend.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/frontend.ts similarity index 98% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/frontend.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/frontend.ts index f0037014671..9833ff753c1 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/frontend.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/frontend.ts @@ -9,7 +9,7 @@ import { CheckboxListContext } from '@woocommerce/interactivity-components/check /** * Internal dependencies */ -import { navigate } from '../../frontend'; +import { navigate } from '../product-filter/frontend'; const getUrl = ( activeFilters: string ) => { const url = new URL( window.location.href ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/index.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/index.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/index.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/preview.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/preview.tsx similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/preview.tsx rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/preview.tsx diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/style.scss similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/style.scss rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/style.scss diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/types.ts similarity index 100% rename from plugins/woocommerce-blocks/assets/js/blocks/product-filter/inner-blocks/stock-filter/types.ts rename to plugins/woocommerce-blocks/assets/js/blocks/product-filters/inner-blocks/stock-filter/types.ts diff --git a/plugins/woocommerce-blocks/bin/webpack-entries.js b/plugins/woocommerce-blocks/bin/webpack-entries.js index 349468e1659..a3adb0662fc 100644 --- a/plugins/woocommerce-blocks/bin/webpack-entries.js +++ b/plugins/woocommerce-blocks/bin/webpack-entries.js @@ -85,40 +85,43 @@ const blocks = { }, 'single-product': {}, 'stock-filter': {}, - 'product-filter': { - isExperimental: true, - }, 'product-filters': { isExperimental: true, }, + 'product-filter': { + isExperimental: true, + customDir: 'product-filters/inner-blocks/product-filter', + }, 'product-filters-overlay': { isExperimental: true, + customDir: 'product-filters/inner-blocks/overlay', }, 'product-filters-overlay-navigation': { isExperimental: true, + customDir: 'product-filters/inner-blocks/overlay-navigation', }, 'product-filter-stock-status': { isExperimental: true, - customDir: 'product-filter/inner-blocks/stock-filter', + customDir: 'product-filters/inner-blocks/stock-filter', }, 'product-filter-price': { - customDir: 'product-filter/inner-blocks/price-filter', + customDir: 'product-filters/inner-blocks/price-filter', isExperimental: true, }, 'product-filter-attribute': { - customDir: 'product-filter/inner-blocks/attribute-filter', + customDir: 'product-filters/inner-blocks/attribute-filter', isExperimental: true, }, 'product-filter-rating': { - customDir: 'product-filter/inner-blocks/rating-filter', + customDir: 'product-filters/inner-blocks/rating-filter', isExperimental: true, }, 'product-filter-active': { - customDir: 'product-filter/inner-blocks/active-filters', + customDir: 'product-filters/inner-blocks/active-filters', isExperimental: true, }, 'product-filter-clear-button': { - customDir: 'product-filter/inner-blocks/clear-button', + customDir: 'product-filters/inner-blocks/clear-button', isExperimental: true, }, 'order-confirmation-summary': { diff --git a/plugins/woocommerce/changelog/update-product-filters-folder-structure b/plugins/woocommerce/changelog/update-product-filters-folder-structure new file mode 100644 index 00000000000..4904e404d8e --- /dev/null +++ b/plugins/woocommerce/changelog/update-product-filters-folder-structure @@ -0,0 +1,5 @@ +Significance: patch +Type: update +Comment: Update the folder structure of new filter blocks. + + From a5e9744ed54ece107d1f528bb0a0315527265db4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 01:04:09 +0700 Subject: [PATCH 156/185] Delete changelog files based on PR 51001 (#51039) Delete changelog files for 51001 Co-authored-by: WooCommerce Bot --- .../woocommerce/changelog/fix-50958-non-tracked-stock-emails | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 plugins/woocommerce/changelog/fix-50958-non-tracked-stock-emails diff --git a/plugins/woocommerce/changelog/fix-50958-non-tracked-stock-emails b/plugins/woocommerce/changelog/fix-50958-non-tracked-stock-emails deleted file mode 100644 index 1df85f4876b..00000000000 --- a/plugins/woocommerce/changelog/fix-50958-non-tracked-stock-emails +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fix -Comment: This is a further fix for #49583, which has not yet been released - - From 3a2a812e1d6290137b7ed5ae7a7c79b23a9abeb2 Mon Sep 17 00:00:00 2001 From: Ivan Stojadinov Date: Thu, 29 Aug 2024 21:05:30 +0200 Subject: [PATCH 157/185] [e2e tests] External sites - update /merchant tests, part 1 (#51014) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dismiss "Choose a pattern" if present * Cover "New in store" for PRessable * Handle error for `api.delete( coupons/ )` * Check if `Select an option…` is available * Expand Pressable suite * Add changefile(s) from automation for the following project(s): woocommerce * Missed one spec, adding it now * Handle "Choose a pattern" popup * Use `closeChoosePatternModal` instead * Remove comments * Add missing `throw` error * Revert to check `Browse store` link, after updating template on Pressable --------- Co-authored-by: github-actions --- ...4-e2e-external-sites-update-merchant-tests-pt1 | 4 ++++ .../envs/default-pressable/playwright.config.js | 5 +++++ .../tests/merchant/create-cart-block.spec.js | 3 +++ .../tests/merchant/create-checkout-block.spec.js | 3 +++ .../e2e-pw/tests/merchant/create-coupon.spec.js | 10 +++++++++- .../e2e-pw/tests/merchant/create-order.spec.js | 15 +++++++++++---- 6 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 plugins/woocommerce/changelog/51014-e2e-external-sites-update-merchant-tests-pt1 diff --git a/plugins/woocommerce/changelog/51014-e2e-external-sites-update-merchant-tests-pt1 b/plugins/woocommerce/changelog/51014-e2e-external-sites-update-merchant-tests-pt1 new file mode 100644 index 00000000000..180673a625b --- /dev/null +++ b/plugins/woocommerce/changelog/51014-e2e-external-sites-update-merchant-tests-pt1 @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Update /merchant tests (first five files), so they are passing against Pressable env. \ No newline at end of file diff --git a/plugins/woocommerce/tests/e2e-pw/envs/default-pressable/playwright.config.js b/plugins/woocommerce/tests/e2e-pw/envs/default-pressable/playwright.config.js index 988e4d3bbea..b0747f37c30 100644 --- a/plugins/woocommerce/tests/e2e-pw/envs/default-pressable/playwright.config.js +++ b/plugins/woocommerce/tests/e2e-pw/envs/default-pressable/playwright.config.js @@ -16,6 +16,11 @@ config = { '**/admin-marketing/**/*.spec.js', '**/admin-tasks/**/*.spec.js', '**/customize-store/**/*.spec.js', + '**/merchant/command-palette.spec.js', + '**/merchant/create-cart-block.spec.js', + '**/merchant/create-checkout-block.spec.js', + '**/merchant/create-coupon.spec.js', + '**/merchant/create-order.spec.js', ], grepInvert: /@skip-on-default-pressable/, }, diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-cart-block.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-cart-block.spec.js index b262e740846..1f612946ce5 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-cart-block.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-cart-block.spec.js @@ -5,6 +5,7 @@ const { insertBlock, transformIntoBlocks, publishPage, + closeChoosePatternModal, } = require( '../../utils/editor' ); const { getInstalledWordPressVersion } = require( '../../utils/wordpress' ); @@ -23,6 +24,8 @@ test.describe( } ) => { await goToPageEditor( { page } ); + await closeChoosePatternModal( { page } ); + await fillPageTitle( page, testPage.title ); const wordPressVersion = await getInstalledWordPressVersion(); await insertBlock( page, 'Classic Cart', wordPressVersion ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js index 23317b1a834..53479325a1b 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js @@ -7,6 +7,7 @@ const { transformIntoBlocks, publishPage, openEditorSettings, + closeChoosePatternModal, } = require( '../../utils/editor' ); const { getInstalledWordPressVersion } = require( '../../utils/wordpress' ); @@ -74,6 +75,8 @@ test.describe( } ) => { await goToPageEditor( { page } ); + await closeChoosePatternModal( { page } ); + await fillPageTitle( page, testPage.title ); const wordPressVersion = await getInstalledWordPressVersion(); await insertBlock( page, 'Classic Checkout', wordPressVersion ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js index 2630674a42b..785f5c0d6b3 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js @@ -35,7 +35,15 @@ const test = baseTest.extend( { coupon: async ( { api }, use ) => { const coupon = {}; await use( coupon ); - await api.delete( `coupons/${ coupon.id }`, { force: true } ); + await api + .delete( `coupons/${ coupon.id }`, { force: true } ) + .then( ( response ) => { + console.log( 'Delete successful:', response.data ); + } ) + .catch( ( error ) => { + console.log( 'Error response data:', error.response.data ); + throw new Error( error.response.data ); + } ); }, } ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-order.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-order.spec.js index aa33c49f167..087e95556b7 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-order.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-order.spec.js @@ -299,10 +299,17 @@ test.describe( await page .getByRole( 'textbox', { name: 'Postcode' } ) .fill( '12345' ); - await page - .getByRole( 'textbox', { name: 'Select an option…' } ) - .click(); - await page.getByRole( 'option', { name: 'Florida' } ).click(); + // eslint-disable-next-line playwright/no-conditional-in-test + if ( + await page + .getByRole( 'textbox', { name: 'Select an option…' } ) + .isVisible() + ) { + await page + .getByRole( 'textbox', { name: 'Select an option…' } ) + .click(); + await page.getByRole( 'option', { name: 'Florida' } ).click(); + } await page .getByRole( 'textbox', { name: 'Email address' } ) .fill( 'elbarto@example.com' ); From a40f87b9ec297f65abd9c3f70fcd486190e26449 Mon Sep 17 00:00:00 2001 From: Gabriel Manussakis <9420947+Manussakis@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:55:23 -0300 Subject: [PATCH 158/185] [Accessibility] Fix typo in initCustomFieldsToogle variable name (#48652) * Fix typo in initCustomFieldsToogle variable name * Add changelog file --------- Co-authored-by: Daniel W. Robert --- .../fix-misspelling-in-initCustomFieldsToogle-variable | 4 ++++ packages/js/product-editor/src/blocks/index.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 packages/js/product-editor/changelog/fix-misspelling-in-initCustomFieldsToogle-variable diff --git a/packages/js/product-editor/changelog/fix-misspelling-in-initCustomFieldsToogle-variable b/packages/js/product-editor/changelog/fix-misspelling-in-initCustomFieldsToogle-variable new file mode 100644 index 00000000000..81ef2df71bd --- /dev/null +++ b/packages/js/product-editor/changelog/fix-misspelling-in-initCustomFieldsToogle-variable @@ -0,0 +1,4 @@ +Significance: minor +Type: tweak + +Fix typo in initCustomFieldsToogle variable name diff --git a/packages/js/product-editor/src/blocks/index.ts b/packages/js/product-editor/src/blocks/index.ts index e6cdbf926a8..80c8f4b2a50 100644 --- a/packages/js/product-editor/src/blocks/index.ts +++ b/packages/js/product-editor/src/blocks/index.ts @@ -1,6 +1,6 @@ export { init as initCatalogVisibility } from './product-fields/catalog-visibility'; export { init as initCustomFields } from './product-fields/custom-fields'; -export { init as initCustomFieldsToogle } from './product-fields/custom-fields-toggle'; +export { init as initCustomFieldsToggle } from './product-fields/custom-fields-toggle'; export { init as initCheckbox } from './generic/checkbox'; export { init as initCollapsible } from './generic/collapsible'; export { init as initConditional } from './generic/conditional'; From 062c4ed76aeb7d3789e81318ad3d8bec11ac5f3e Mon Sep 17 00:00:00 2001 From: Karol Manijak <20098064+kmanijak@users.noreply.github.com> Date: Fri, 30 Aug 2024 07:47:03 +0200 Subject: [PATCH 159/185] Migrate Product Price to `block.json` (#50905) * Migrate Product Price to block.json * Add changelog * Update block references * Update block references and doc manifest * Add shared config properties to Product Price block.json * Update block references and docs manifest --- docs/building-a-woo-store/block-references.md | 11 ++++++ docs/docs-manifest.json | 4 +-- .../product-elements/price/attributes.ts | 29 ---------------- .../blocks/product-elements/price/block.json | 34 +++++++++++++++++++ .../product-elements/price/constants.tsx | 17 ---------- .../blocks/product-elements/price/index.tsx | 34 ++++++++----------- .../dev-46917-migrate-to-block-json-price | 4 +++ 7 files changed, 66 insertions(+), 67 deletions(-) delete mode 100644 plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/attributes.ts create mode 100644 plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.json delete mode 100644 plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/constants.tsx create mode 100644 plugins/woocommerce/changelog/dev-46917-migrate-to-block-json-price diff --git a/docs/building-a-woo-store/block-references.md b/docs/building-a-woo-store/block-references.md index 0cf96318ebc..5ae993bb975 100644 --- a/docs/building-a-woo-store/block-references.md +++ b/docs/building-a-woo-store/block-references.md @@ -53,6 +53,17 @@ Display the main product image. - **Supports:** - **Attributes:** aspectRatio, height, imageSizing, isDescendentOfQueryLoop, isDescendentOfSingleProductBlock, productId, saleBadgeAlign, scale, showProductLink, showSaleBadge, width +## Product Price - woocommerce/product-price + +Display the price of a product. + +- **Name:** woocommerce/product-price +- **Category:** woocommerce-product-elements +- **Ancestor:** woocommerce/all-products,woocommerce/single-product,woocommerce/product-template,core/post-template +- **Parent:** +- **Supports:** ~~html~~ +- **Attributes:** isDescendentOfQueryLoop, isDescendentOfSingleProductBlock, isDescendentOfSingleProductTemplate, productId, textAlign + ## Product Details - woocommerce/product-details Display a product's description, attributes, and reviews. diff --git a/docs/docs-manifest.json b/docs/docs-manifest.json index 6e8e25bf2e6..6ef73f9e485 100644 --- a/docs/docs-manifest.json +++ b/docs/docs-manifest.json @@ -74,7 +74,7 @@ "post_title": "Blocks reference", "menu_title": "Blocks Reference", "edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/building-a-woo-store/block-references.md", - "hash": "a33fe5766283aaa70154077692a180319110e133ad430bf8dda3032455bad45c", + "hash": "329f17097ce67074a915d7814b2363e8b9e908910c1f7b196c8f4fd8594cc55c", "url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/building-a-woo-store/block-references.md", "id": "1fbe91d7fa4fafaf35f0297e4cee1e7958756aed" }, @@ -1804,5 +1804,5 @@ "categories": [] } ], - "hash": "0b0ae9b9ed454ab234a5f053f6efb37bafb3e90f1c98f6488263c019f552697b" + "hash": "2ecf48b6181dae0526b3858df889bce4e6ee425e10f2c43d151771d845c5a948" } \ No newline at end of file diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/attributes.ts b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/attributes.ts deleted file mode 100644 index 0acba812f16..00000000000 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/attributes.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * External dependencies - */ -import { BlockAttributes } from '@wordpress/blocks'; - -export const blockAttributes: BlockAttributes = { - productId: { - type: 'number', - default: 0, - }, - isDescendentOfQueryLoop: { - type: 'boolean', - default: false, - }, - textAlign: { - type: 'string', - default: '', - }, - isDescendentOfSingleProductTemplate: { - type: 'boolean', - default: false, - }, - isDescendentOfSingleProductBlock: { - type: 'boolean', - default: false, - }, -}; - -export default blockAttributes; diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.json b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.json new file mode 100644 index 00000000000..02036c30be1 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/block.json @@ -0,0 +1,34 @@ +{ + "name": "woocommerce/product-price", + "version": "1.0.0", + "title": "Product Price", + "description": "Display the price of a product.", + "category": "woocommerce-product-elements", + "attributes": { + "productId": { "type": "number", "default": 0 }, + "isDescendentOfQueryLoop": { "type": "boolean", "default": false }, + "textAlign": { "type": "string", "default": "" }, + "isDescendentOfSingleProductTemplate": { + "type": "boolean", + "default": false + }, + "isDescendentOfSingleProductBlock": { + "type": "boolean", + "default": false + } + }, + "usesContext": [ "query", "queryId", "postId" ], + "keywords": [ "WooCommerce" ], + "textdomain": "woocommerce", + "apiVersion": 3, + "supports": { + "html": false + }, + "ancestor": [ + "woocommerce/all-products", + "woocommerce/single-product", + "woocommerce/product-template", + "core/post-template" + ], + "$schema": "https://schemas.wp.org/trunk/block.json" +} diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/constants.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/constants.tsx deleted file mode 100644 index 1aa64d8e2d5..00000000000 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/constants.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { currencyDollar, Icon } from '@wordpress/icons'; - -export const BLOCK_TITLE: string = __( 'Product Price', 'woocommerce' ); -export const BLOCK_ICON: JSX.Element = ( - -); -export const BLOCK_DESCRIPTION: string = __( - 'Display the price of a product.', - 'woocommerce' -); diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/index.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/index.tsx index a2e8a06f520..700ed125a99 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/price/index.tsx @@ -2,33 +2,29 @@ * External dependencies */ import { registerBlockSingleProductTemplate } from '@woocommerce/atomic-utils'; +import { currencyDollar, Icon } from '@wordpress/icons'; /** * Internal dependencies */ import sharedConfig from '../shared/config'; import edit from './edit'; -import attributes from './attributes'; import { supports } from './supports'; -import { - BLOCK_TITLE as title, - BLOCK_ICON as icon, - BLOCK_DESCRIPTION as description, -} from './constants'; - -const blockConfig = { - ...sharedConfig, - title, - description, - usesContext: [ 'query', 'queryId', 'postId' ], - icon: { src: icon }, - attributes, - supports, - edit, -}; +import metadata from './block.json'; registerBlockSingleProductTemplate( { - blockName: 'woocommerce/product-price', - blockSettings: blockConfig, + blockName: metadata.name, + blockMetadata: metadata, + blockSettings: { + ...sharedConfig, + supports, + icon: ( + + ), + edit, + }, isAvailableOnPostEditor: true, } ); diff --git a/plugins/woocommerce/changelog/dev-46917-migrate-to-block-json-price b/plugins/woocommerce/changelog/dev-46917-migrate-to-block-json-price new file mode 100644 index 00000000000..037f08ea6ae --- /dev/null +++ b/plugins/woocommerce/changelog/dev-46917-migrate-to-block-json-price @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Product Price: migrate to block.json From ff197207ef9e5a6d84be365440497ba9ac0785a3 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Fri, 30 Aug 2024 08:48:54 +0200 Subject: [PATCH 160/185] Product Collection: Don't render when empty unless the no results block is present (#50404) * Disable PC render when content empty unless no results block is present * Introduce empty PC classname * Add E2E test * Add changelog entry * Ensure the render is preserved as expected * Do not render empty div * Update tests * Try a different logic * Add hint to the docblock * Remove obsolete e2e test * Update render handler name to acknowledge context * Fix tests failing due to recent v3 update * Restore block interactivity --------- Co-authored-by: Manish Menaria --- .../product-collection.block_theme.spec.ts | 81 +++++++++++++++++++ .../fix-pc-prevent-rendering-on-empty-query | 4 + .../Blocks/BlockTypes/ProductCollection.php | 76 ++++++++++++++++- 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 plugins/woocommerce/changelog/fix-pc-prevent-rendering-on-empty-query diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts index 788f27b123a..af0839c5ca1 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts @@ -81,6 +81,87 @@ test.describe( 'Product Collection', () => { ).toBeVisible(); } ); + test.describe( 'when no results are found', () => { + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test( 'does not render', async ( { page, editor, pageObject } ) => { + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( 'featured' ); + await pageObject.addFilter( 'Price Range' ); + await pageObject.setPriceRange( { + max: '1', + } ); + + const featuredBlock = editor.canvas.getByLabel( 'Block: Featured' ); + + await expect( + featuredBlock.getByText( 'Featured products' ) + ).toBeVisible(); + // The "No results found" info is rendered in editor for all collections. + await expect( + featuredBlock.getByText( 'No results found' ) + ).toBeVisible(); + + await pageObject.publishAndGoToFrontend(); + + const content = page.locator( 'main' ); + + await expect( content ).not.toContainText( 'Featured products' ); + await expect( content ).not.toContainText( 'No results found' ); + } ); + + // This test ensures the runtime render state is correctly reset for + // each block. + test( 'does not prevent subsequent blocks from render', async ( { + page, + pageObject, + } ) => { + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( 'featured' ); + await pageObject.addFilter( 'Price Range' ); + await pageObject.setPriceRange( { + max: '1', + } ); + + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( 'topRated' ); + + await pageObject.refreshLocators( 'editor' ); + await expect( pageObject.products ).toHaveCount( 5 ); + + await pageObject.publishAndGoToFrontend(); + + await pageObject.refreshLocators( 'frontend' ); + await expect( pageObject.products ).toHaveCount( 5 ); + await expect( page.locator( 'main' ) ).not.toContainText( + 'Featured products' + ); + } ); + + test( 'renders if No Results block is present', async ( { + page, + editor, + pageObject, + } ) => { + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( 'productCatalog' ); + await pageObject.addFilter( 'Price Range' ); + await pageObject.setPriceRange( { + max: '1', + } ); + + await expect( + editor.canvas.getByText( 'No results found' ) + ).toBeVisible(); + + await pageObject.publishAndGoToFrontend(); + + await expect( page.getByText( 'No results found' ) ).toBeVisible(); + } ); + } ); + test.describe( 'Renders correctly with all Product Elements', () => { const expectedProductContent = [ 'Beanie', // core/post-title diff --git a/plugins/woocommerce/changelog/fix-pc-prevent-rendering-on-empty-query b/plugins/woocommerce/changelog/fix-pc-prevent-rendering-on-empty-query new file mode 100644 index 00000000000..bbdaf94ece0 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-pc-prevent-rendering-on-empty-query @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Product Collection: Don't render when empty unless the no results block is present. diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection.php index bf42d344a52..f2f9f72328a 100644 --- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection.php +++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection.php @@ -47,6 +47,18 @@ class ProductCollection extends AbstractBlock { protected $custom_order_opts = array( 'popularity', 'rating' ); + /** + * The render state of the product collection block. + * + * These props are runtime-based and reinitialize for every block on a page. + * + * @var array + */ + private $render_state = array( + 'has_results' => false, + 'has_no_results_block' => false, + ); + /** * Initialize this block type. * @@ -80,8 +92,30 @@ class ProductCollection extends AbstractBlock { // Provide location context into block's context. add_filter( 'render_block_context', array( $this, 'provide_location_context_for_inner_blocks' ), 11, 1 ); + // Disable block render if the ProductTemplate block is empty. + add_filter( + 'render_block_woocommerce/product-template', + function ( $html ) { + $this->render_state['has_results'] = ! empty( $html ); + return $html; + }, + 100, + 1 + ); + + // Enable block render if the ProductCollectionNoResults block is rendered. + add_filter( + 'render_block_woocommerce/product-collection-no-results', + function ( $html ) { + $this->render_state['has_no_results_block'] = ! empty( $html ); + return $html; + }, + 100, + 1 + ); + // Interactivity API: Add navigation directives to the product collection block. - add_filter( 'render_block_woocommerce/product-collection', array( $this, 'enhance_product_collection_with_interactivity' ), 10, 2 ); + add_filter( 'render_block_woocommerce/product-collection', array( $this, 'handle_rendering' ), 10, 2 ); add_filter( 'render_block_core/query-pagination', array( $this, 'add_navigation_link_directives' ), 10, 3 ); add_filter( 'posts_clauses', array( $this, 'add_price_range_filter_posts_clauses' ), 10, 2 ); @@ -90,6 +124,46 @@ class ProductCollection extends AbstractBlock { add_filter( 'render_block_data', array( $this, 'disable_enhanced_pagination' ), 10, 1 ); } + /** + * Handle the rendering of the block. + * + * @param string $block_content The block content about to be rendered. + * @param array $block The block being rendered. + * + * @return string + */ + public function handle_rendering( $block_content, $block ) { + if ( $this->should_prevent_render() ) { + return ''; // Prevent rendering. + } + + // Reset the render state for the next render. + $this->reset_render_state(); + + return $this->enhance_product_collection_with_interactivity( $block_content, $block ); + } + + /** + * Check if the block should be prevented from rendering. + * + * @return bool + */ + private function should_prevent_render() { + return ! $this->render_state['has_results'] && ! $this->render_state['has_no_results_block']; + } + + /** + * Reset the render state. + */ + private function reset_render_state() { + $this->render_state = array( + 'has_results' => false, + 'has_no_results_block' => false, + ); + } + + + /** * Provides the location context to each inner block of the product collection block. * Hint: Only blocks using the 'query' context will be affected. From 0f1634d6dadb6b397ea8e808e1af993d57fd1a37 Mon Sep 17 00:00:00 2001 From: Gabriel Manussakis <9420947+Manussakis@users.noreply.github.com> Date: Fri, 30 Aug 2024 05:14:22 -0300 Subject: [PATCH 161/185] [Accessibility] Trap focus inside the product gallery modal (#50730) * Add i18n_open_product_gallery prop to wc_single_product_params * Trap focus inside the product gallery modal * Ensure the product gallery controls are always visible * Add changelog file * Add space before parameter * Early return if there is no elements enough to trap focus * Revert changes on the gallery trigger link * Remove unnecessary white sopace * Fix trap focus when the arrow buttons are hidden * Remove usage of the Photoswipe destroy event --- plugins/woocommerce/changelog/fix-43605 | 4 ++ .../legacy/js/frontend/single-product.js | 69 ++++++++++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-43605 diff --git a/plugins/woocommerce/changelog/fix-43605 b/plugins/woocommerce/changelog/fix-43605 new file mode 100644 index 00000000000..ad1d926bd91 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-43605 @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Trap focus inside the product gallery modal. diff --git a/plugins/woocommerce/client/legacy/js/frontend/single-product.js b/plugins/woocommerce/client/legacy/js/frontend/single-product.js index 6b5c99cd8e8..e8adcc662fc 100644 --- a/plugins/woocommerce/client/legacy/js/frontend/single-product.js +++ b/plugins/woocommerce/client/legacy/js/frontend/single-product.js @@ -127,6 +127,8 @@ jQuery( function( $ ) { this.onResetSlidePosition = this.onResetSlidePosition.bind( this ); this.getGalleryItems = this.getGalleryItems.bind( this ); this.openPhotoswipe = this.openPhotoswipe.bind( this ); + this.trapFocusPhotoswipe = this.trapFocusPhotoswipe.bind( this ); + this.handlePswpTrapFocus = this.handlePswpTrapFocus.bind( this ); if ( this.flexslider_enabled ) { this.initFlexslider( args.flexslider ); @@ -307,8 +309,10 @@ jQuery( function( $ ) { e.preventDefault(); var pswpElement = $( '.pswp' )[0], - items = this.getGalleryItems(), - eventTarget = $( e.target ), + items = this.getGalleryItems(), + eventTarget = $( e.target ), + currentTarget = e.currentTarget, + self = this, clicked; if ( 0 < eventTarget.closest( '.woocommerce-product-gallery__trigger' ).length ) { @@ -326,14 +330,73 @@ jQuery( function( $ ) { } captionEl.children[0].textContent = item.title; return true; - } + }, + timeToIdle: 0, // Ensure the gallery controls are always visible to avoid keyboard navigation issues. }, wc_single_product_params.photoswipe_options ); // Initializes and opens PhotoSwipe. var photoswipe = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options ); + + photoswipe.listen( 'afterInit', function() { + self.trapFocusPhotoswipe( true ); + }); + + photoswipe.listen( 'close', function() { + self.trapFocusPhotoswipe( false ); + currentTarget.focus(); + }); + photoswipe.init(); }; + /** + * Control focus in photoswipe modal. + * + * @param {boolean} trapFocus - Whether to trap focus or not. + */ + ProductGallery.prototype.trapFocusPhotoswipe = function( trapFocus ) { + var pswp = document.querySelector( '.pswp' ); + + if ( ! pswp ) { + return; + } + + if ( trapFocus ) { + pswp.addEventListener( 'keydown', this.handlePswpTrapFocus ); + } else { + pswp.removeEventListener( 'keydown', this.handlePswpTrapFocus ); + } + }; + + /** + * Handle keydown event in photoswipe modal. + */ + ProductGallery.prototype.handlePswpTrapFocus = function( e ) { + var allFocusablesEls = e.currentTarget.querySelectorAll( 'button:not([disabled])' ); + var filteredFocusablesEls = Array.from( allFocusablesEls ).filter( function( btn ) { + return btn.style.display !== 'none' && window.getComputedStyle( btn ).display !== 'none'; + } ); + + if ( 1 >= filteredFocusablesEls.length ) { + return; + } + + var firstTabStop = filteredFocusablesEls[0]; + var lastTabStop = filteredFocusablesEls[filteredFocusablesEls.length - 1]; + + if ( e.key === 'Tab' ) { + if ( e.shiftKey ) { + if ( document.activeElement === firstTabStop ) { + e.preventDefault(); + lastTabStop.focus(); + } + } else if ( document.activeElement === lastTabStop ) { + e.preventDefault(); + firstTabStop.focus(); + } + } + }; + /** * Function to call wc_product_gallery on jquery selector. */ From 40cde50879db7618b79067bcf4ceabe03b0eea69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Rinc=C3=B3n?= Date: Fri, 30 Aug 2024 10:23:28 +0200 Subject: [PATCH 162/185] `Product SKU` improvements (#51033) * Add new prefix and suffix attributes * Add editable prefix & suffix rich text fields * Remove the uppercase style from prefix and suffix * Render the prefix and suffix in the front end * Fix lint errors * Handle old sku block without prefix and suffix * Improve the editor styles * Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce * Use wp_kses_post to filter and format the suffix and perfix * Address extra space when empty and better escaping --------- Co-authored-by: github-actions --- .../blocks/product-elements/sku/attributes.ts | 8 +++++ .../blocks/product-elements/sku/block.tsx | 31 +++++++++++++++++-- .../blocks/product-elements/sku/edit.tsx | 3 +- .../blocks/product-elements/sku/editor.scss | 4 +++ .../blocks/product-elements/sku/index.tsx | 3 ++ .../blocks/product-elements/sku/style.scss | 5 ++- .../blocks/product-elements/sku/types.ts | 2 ++ .../51033-47922-product-sku-improvements | 4 +++ .../src/Blocks/BlockTypes/ProductSKU.php | 19 ++++++++++-- 9 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/editor.scss create mode 100644 plugins/woocommerce/changelog/51033-47922-product-sku-improvements diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/attributes.ts b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/attributes.ts index d70b39f1a99..0e0ae0bfdfe 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/attributes.ts +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/attributes.ts @@ -24,6 +24,14 @@ export const blockAttributes: BlockAttributes = { type: 'boolean', default: false, }, + prefix: { + type: 'string', + default: 'SKU:', + }, + suffix: { + type: 'string', + default: '', + }, }; export default blockAttributes; diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/block.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/block.tsx index 329475b0e32..d85ddbab0ac 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/block.tsx @@ -1,7 +1,6 @@ /** * External dependencies */ -import { __ } from '@wordpress/i18n'; import clsx from 'clsx'; import { useInnerBlockLayoutContext, @@ -10,6 +9,8 @@ import { import { withProductDataContext } from '@woocommerce/shared-hocs'; import type { HTMLAttributes } from 'react'; import { useStyleProps } from '@woocommerce/base-hooks'; +import { RichText } from '@wordpress/block-editor'; +import type { BlockEditProps } from '@wordpress/blocks'; /** * Internal dependencies @@ -17,18 +18,24 @@ import { useStyleProps } from '@woocommerce/base-hooks'; import './style.scss'; import type { Attributes } from './types'; -type Props = Attributes & HTMLAttributes< HTMLDivElement >; +type Props = BlockEditProps< Attributes > & HTMLAttributes< HTMLDivElement >; const Preview = ( { + setAttributes, parentClassName, sku, className, style, + prefix, + suffix, }: { + setAttributes: ( attributes: Record< string, unknown > ) => void; parentClassName: string; sku: string; className?: string | undefined; style?: React.CSSProperties | undefined; + prefix?: string; + suffix?: string; } ) => (
        - { __( 'SKU:', 'woocommerce' ) } { sku } + setAttributes( { prefix: value } ) } + /> + { sku } + setAttributes( { suffix: value } ) } + />
        ); @@ -50,9 +69,12 @@ const Block = ( props: Props ): JSX.Element | null => { if ( props.isDescendentOfSingleProductTemplate ) { return ( ); } @@ -63,9 +85,12 @@ const Block = ( props: Props ): JSX.Element | null => { return ( - +
        ); diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/editor.scss b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/editor.scss new file mode 100644 index 00000000000..4dbdbfa5f37 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/editor.scss @@ -0,0 +1,4 @@ +.wc-block-components-product-sku strong { + margin-left: $gap-smallest; + margin-right: $gap-smallest; +} diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx index 2b631c74dcd..3b461c0f052 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/index.tsx @@ -29,6 +29,9 @@ const blockConfig: BlockConfiguration = { 'woocommerce/product-meta', ], edit, + save() { + return null; + }, supports, }; diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/style.scss b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/style.scss index d32bc9ca521..8aa99c856b3 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/style.scss +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/style.scss @@ -1,6 +1,9 @@ .wc-block-components-product-sku { display: block; - text-transform: uppercase; @include font-size(small); overflow-wrap: break-word; + + strong { + text-transform: uppercase; + } } diff --git a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/types.ts b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/types.ts index a43531d141f..ec603507389 100644 --- a/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/types.ts +++ b/plugins/woocommerce-blocks/assets/js/atomic/blocks/product-elements/sku/types.ts @@ -5,4 +5,6 @@ export interface Attributes { isDescendentOfSingleProductBlock: boolean; showProductSelector: boolean; isDescendantOfAllProducts: boolean; + prefix: string; + suffix: string; } diff --git a/plugins/woocommerce/changelog/51033-47922-product-sku-improvements b/plugins/woocommerce/changelog/51033-47922-product-sku-improvements new file mode 100644 index 00000000000..1849a43e716 --- /dev/null +++ b/plugins/woocommerce/changelog/51033-47922-product-sku-improvements @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Product SKU block: add editable prefixes and suffixes. \ No newline at end of file diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductSKU.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductSKU.php index 1475a005217..50e748f646e 100644 --- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductSKU.php +++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductSKU.php @@ -69,14 +69,27 @@ class ProductSKU extends AbstractBlock { $styles_and_classes = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes ); + $prefix = isset( $attributes['prefix'] ) ? wp_kses_post( ( $attributes['prefix'] ) ) : __( 'SKU: ', 'woocommerce' ); + if ( ! empty( $prefix ) ) { + $prefix = sprintf( '%s', $prefix ); + } + + $suffix = isset( $attributes['suffix'] ) ? wp_kses_post( ( $attributes['suffix'] ) ) : ''; + if ( ! empty( $suffix ) ) { + $suffix = sprintf( '%s', $suffix ); + } + return sprintf( '
        - SKU: - %3$s + %3$s + %4$s + %5$s
        ', esc_attr( $styles_and_classes['classes'] ), esc_attr( $styles_and_classes['styles'] ?? '' ), - $product_sku + $prefix, + $product_sku, + $suffix ); } } From 5999ea671661b4faa1fc4dd288b84d77755b955d Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 30 Aug 2024 16:42:28 +0530 Subject: [PATCH 163/185] Add filter to overwrite response of `wc_rest_should_load_namespace` (#50902) * Add filter to allow overwriting `wc_rest_should_load_namespace`. * Unit tests + changelog. * Add doc block. * Update version number. Co-authored-by: Corey McKrill <916023+coreymckrill@users.noreply.github.com> --------- Co-authored-by: Corey McKrill <916023+coreymckrill@users.noreply.github.com> --- plugins/woocommerce/changelog/fix-50891 | 4 ++++ .../woocommerce/includes/wc-rest-functions.php | 14 +++++++++++--- .../php/includes/wc-rest-functions-test.php | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-50891 diff --git a/plugins/woocommerce/changelog/fix-50891 b/plugins/woocommerce/changelog/fix-50891 new file mode 100644 index 00000000000..33cc44e00b0 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50891 @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Add filter for response of `wc_rest_should_load_namespace` function to allow loading namespaces. diff --git a/plugins/woocommerce/includes/wc-rest-functions.php b/plugins/woocommerce/includes/wc-rest-functions.php index 3eeec672a27..e9b3055cc9f 100644 --- a/plugins/woocommerce/includes/wc-rest-functions.php +++ b/plugins/woocommerce/includes/wc-rest-functions.php @@ -410,8 +410,6 @@ function wc_rest_should_load_namespace( string $ns, string $rest_route = '' ): b 'wc/private', ); - // We can consider allowing filtering this list in the future. - $known_namespace_request = false; foreach ( $known_namespaces as $known_namespace ) { if ( str_starts_with( $rest_route, $known_namespace ) ) { @@ -424,5 +422,15 @@ function wc_rest_should_load_namespace( string $ns, string $rest_route = '' ): b return true; } - return str_starts_with( $rest_route, $ns ); + /** + * Filters whether a namespace should be loaded. + * + * @param bool $should_load True if the namespace should be loaded, false otherwise. + * @param string $ns The namespace to check. + * @param string $rest_route The REST route being checked. + * @param array $known_namespaces Known namespaces that we know are safe to not load if the request is not for them. + * + * @since 9.4 + */ + return apply_filters( 'wc_rest_should_load_namespace', str_starts_with( $rest_route, $ns ), $ns, $rest_route, $known_namespaces ); } diff --git a/plugins/woocommerce/tests/php/includes/wc-rest-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-rest-functions-test.php index d5938d7fbcb..41d2dd8dfc4 100644 --- a/plugins/woocommerce/tests/php/includes/wc-rest-functions-test.php +++ b/plugins/woocommerce/tests/php/includes/wc-rest-functions-test.php @@ -27,4 +27,22 @@ class WCRestFunctionsTest extends WC_Unit_Test_Case { $this->assertFalse( wc_rest_should_load_namespace( 'wc-analytics', 'wc/v2' ) ); $this->assertTrue( wc_rest_should_load_namespace( 'wc/v2', 'wc/v2' ) ); } + + /** + * @testDox Test wc_rest_should_load_namespace known works with preload. + */ + public function test_wc_rest_should_load_namespace_known_works_with_preload() { + $memo = rest_preload_api_request( array(), '/wc/store/v1/cart' ); + $this->assertArrayHasKey( '/wc/store/v1/cart', $memo ); + } + + /** + * @testDox Test wc_rest_should_load_namespace filter. + */ + public function test_wc_rest_should_load_namespace_filter() { + $this->assertFalse( wc_rest_should_load_namespace( 'wc/v1', 'wc/v2' ) ); + add_filter( 'wc_rest_should_load_namespace', '__return_true' ); + $this->assertTrue( wc_rest_should_load_namespace( 'wc/v1', 'wc/v2' ) ); + remove_filter( 'wc_rest_should_load_namespace', '__return_true' ); + } } From 44b5f54d08cf6b2f7c34568464d543e4a26d6174 Mon Sep 17 00:00:00 2001 From: Tom Cafferkey Date: Fri, 30 Aug 2024 12:24:34 +0100 Subject: [PATCH 164/185] Add doc blocks to Products shortcode hooks (#51061) * Add doc blocks to products shortcode woocommerce_before_shop_loop hooks * Improved comments * Add changelog --- .../add-docblocks-to-products-shortcode-hooks | 4 ++++ .../shortcodes/class-wc-shortcode-products.php | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 plugins/woocommerce/changelog/add-docblocks-to-products-shortcode-hooks diff --git a/plugins/woocommerce/changelog/add-docblocks-to-products-shortcode-hooks b/plugins/woocommerce/changelog/add-docblocks-to-products-shortcode-hooks new file mode 100644 index 00000000000..0c79db17c86 --- /dev/null +++ b/plugins/woocommerce/changelog/add-docblocks-to-products-shortcode-hooks @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Added doc blocks to conditionally fired hooks to better explain nuanced behavior diff --git a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php index 9b551b3f2e0..51eed9c2753 100644 --- a/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php +++ b/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php @@ -641,8 +641,13 @@ class WC_Shortcode_Products { do_action( "woocommerce_shortcode_before_{$this->type}_loop", $this->attributes ); - // Fire standard shop loop hooks when paginating results so we can show result counts and so on. if ( wc_string_to_bool( $this->attributes['paginate'] ) ) { + /** + * Fire the standard shop hooks when paginating so we can display result counts etc. + * If the pagination is not enabled, this hook will not be fired. + * + * @since 3.3.1 + */ do_action( 'woocommerce_before_shop_loop' ); } @@ -667,8 +672,13 @@ class WC_Shortcode_Products { $GLOBALS['post'] = $original_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited woocommerce_product_loop_end(); - // Fire standard shop loop hooks when paginating results so we can show result counts and so on. if ( wc_string_to_bool( $this->attributes['paginate'] ) ) { + /** + * Fire the standard shop hooks when paginating so we can display the pagination. + * If the pagination is not enabled, this hook will not be fired. + * + * @since 3.3.1 + */ do_action( 'woocommerce_after_shop_loop' ); } From 7971df1d280fe1da1cf1c04602be0db314928f80 Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Fri, 30 Aug 2024 20:25:52 +0800 Subject: [PATCH 165/185] Enhance WooCommerce version checking for remote logging reliability (#51009) * Enhance WooCommerce version checking using get_plugin_updates() * Update remote logger tool to toggle remote logging feature properly * Add changelog --- .../api/remote-logging/remote-logging.php | 1 + .../changelog/update-move-woo-version-check | 4 + .../changelog/update-move-woo-version-check | 4 + .../src/Internal/Logging/RemoteLogger.php | 74 +++++----- .../src/Internal/Logging/RemoteLoggerTest.php | 129 +++++++++++++----- 5 files changed, 141 insertions(+), 71 deletions(-) create mode 100644 plugins/woocommerce-beta-tester/changelog/update-move-woo-version-check create mode 100644 plugins/woocommerce/changelog/update-move-woo-version-check diff --git a/plugins/woocommerce-beta-tester/api/remote-logging/remote-logging.php b/plugins/woocommerce-beta-tester/api/remote-logging/remote-logging.php index 6e7d9b1487b..80d518e03f2 100644 --- a/plugins/woocommerce-beta-tester/api/remote-logging/remote-logging.php +++ b/plugins/woocommerce-beta-tester/api/remote-logging/remote-logging.php @@ -74,6 +74,7 @@ function toggle_remote_logging( $request ) { update_option( 'woocommerce_feature_remote_logging_enabled', 'yes' ); update_option( 'woocommerce_allow_tracking', 'yes' ); update_option( 'woocommerce_remote_variant_assignment', 1 ); + set_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT, WC()->version ); } else { update_option( 'woocommerce_feature_remote_logging_enabled', 'no' ); } diff --git a/plugins/woocommerce-beta-tester/changelog/update-move-woo-version-check b/plugins/woocommerce-beta-tester/changelog/update-move-woo-version-check new file mode 100644 index 00000000000..6807f1d962f --- /dev/null +++ b/plugins/woocommerce-beta-tester/changelog/update-move-woo-version-check @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Update remote logger tool to toggle remote logging feature properly diff --git a/plugins/woocommerce/changelog/update-move-woo-version-check b/plugins/woocommerce/changelog/update-move-woo-version-check new file mode 100644 index 00000000000..af5e8c0070e --- /dev/null +++ b/plugins/woocommerce/changelog/update-move-woo-version-check @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Enhance WooCommerce version checking for remote logging reliability diff --git a/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php b/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php index 01e71d40e62..3bcb44f4c29 100644 --- a/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php +++ b/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php @@ -20,11 +20,10 @@ use WC_Log_Levels; * @package WooCommerce\Classes */ class RemoteLogger extends \WC_Log_Handler { - const LOG_ENDPOINT = 'https://public-api.wordpress.com/rest/v1.1/logstash'; - const RATE_LIMIT_ID = 'woocommerce_remote_logging'; - const RATE_LIMIT_DELAY = 60; // 1 minute. - const WC_LATEST_VERSION_TRANSIENT = 'latest_woocommerce_version'; - const FETCH_LATEST_VERSION_RETRY = 'fetch_latest_woocommerce_version_retry'; + const LOG_ENDPOINT = 'https://public-api.wordpress.com/rest/v1.1/logstash'; + const RATE_LIMIT_ID = 'woocommerce_remote_logging'; + const RATE_LIMIT_DELAY = 60; // 1 minute. + const WC_NEW_VERSION_TRANSIENT = 'woocommerce_new_version'; /** * Handle a log entry. @@ -150,7 +149,7 @@ class RemoteLogger extends \WC_Log_Handler { return false; } - if ( ! $this->is_latest_woocommerce_version() ) { + if ( ! $this->should_current_version_be_logged() ) { return false; } @@ -221,7 +220,7 @@ class RemoteLogger extends \WC_Log_Handler { self::LOG_ENDPOINT, array( 'body' => wp_json_encode( $body ), - 'timeout' => 2, + 'timeout' => 3, 'headers' => array( 'Content-Type' => 'application/json', ), @@ -256,14 +255,22 @@ class RemoteLogger extends \WC_Log_Handler { * * @return bool */ - private function is_latest_woocommerce_version() { - $latest_wc_version = $this->fetch_latest_woocommerce_version(); + private function should_current_version_be_logged() { + $new_version = get_site_transient( self::WC_NEW_VERSION_TRANSIENT ); - if ( is_null( $latest_wc_version ) ) { - return false; + if ( false === $new_version ) { + $new_version = $this->fetch_new_woocommerce_version(); + // Cache the new version for a week since we want to keep logging in with the same version for a while even if the new version is available. + set_site_transient( self::WC_NEW_VERSION_TRANSIENT, $new_version, WEEK_IN_SECONDS ); } - return version_compare( WC()->version, $latest_wc_version, '>=' ); + if ( ! is_string( $new_version ) || '' === $new_version ) { + // If the new version is not available, we consider the current version to be the latest. + return true; + } + + // If the current version is the latest, we don't want to log errors. + return version_compare( WC()->version, $new_version, '>=' ); } /** @@ -316,45 +323,34 @@ class RemoteLogger extends \WC_Log_Handler { } /** - * Fetch the latest WooCommerce version using the WordPress API and cache it. + * Fetch the new version of WooCommerce from the WordPress API. * - * @return string|null + * @return string|null New version if an update is available, null otherwise. */ - private function fetch_latest_woocommerce_version() { - $cached_version = get_transient( self::WC_LATEST_VERSION_TRANSIENT ); - if ( $cached_version ) { - return $cached_version; + private function fetch_new_woocommerce_version() { + if ( ! function_exists( 'get_plugins' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + if ( ! function_exists( 'get_plugin_updates' ) ) { + require_once ABSPATH . 'wp-admin/includes/update.php'; } - $retry_count = get_transient( self::FETCH_LATEST_VERSION_RETRY ); - if ( false === $retry_count || ! is_numeric( $retry_count ) ) { - $retry_count = 0; - } + $plugin_updates = get_plugin_updates(); - if ( $retry_count >= 3 ) { + // Check if WooCommerce plugin update information is available. + if ( ! is_array( $plugin_updates ) || ! isset( $plugin_updates[ WC_PLUGIN_BASENAME ] ) ) { return null; } - if ( ! function_exists( 'plugins_api' ) ) { - require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; - } - // Fetch the latest version from the WordPress API. - $plugin_info = plugins_api( 'plugin_information', array( 'slug' => 'woocommerce' ) ); + $wc_plugin_update = $plugin_updates[ WC_PLUGIN_BASENAME ]; - if ( is_wp_error( $plugin_info ) ) { - ++$retry_count; - set_transient( self::FETCH_LATEST_VERSION_RETRY, $retry_count, HOUR_IN_SECONDS ); + // Ensure the update object exists and has the required information. + if ( ! $wc_plugin_update || ! isset( $wc_plugin_update->update->new_version ) ) { return null; } - if ( ! empty( $plugin_info->version ) ) { - $latest_version = $plugin_info->version; - set_transient( self::WC_LATEST_VERSION_TRANSIENT, $latest_version, WEEK_IN_SECONDS ); - delete_transient( self::FETCH_LATEST_VERSION_RETRY ); - return $latest_version; - } - - return null; + $new_version = $wc_plugin_update->update->new_version; + return is_string( $new_version ) ? $new_version : null; } /** diff --git a/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php b/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php index 7133f38f5ef..63327438a03 100644 --- a/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php +++ b/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php @@ -35,8 +35,7 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { public function tearDown(): void { $this->cleanup_filters(); delete_option( 'woocommerce_feature_remote_logging_enabled' ); - delete_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT ); - delete_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY ); + delete_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); global $wpdb; $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_rate_limits" ); WC_Cache_Helper::invalidate_cache_group( WC_Rate_Limiter::CACHE_GROUP ); @@ -56,6 +55,7 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { 'plugins_api', 'pre_http_request', 'woocommerce_remote_logger_formatted_log_data', + 'pre_site_transient_update_plugins', ); foreach ( $filters as $filter ) { remove_all_filters( $filter ); @@ -90,18 +90,23 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { */ public function remote_logging_disallowed_provider() { return array( - 'feature flag disabled' => array( + 'feature flag disabled' => array( 'condition' => 'feature flag disabled', 'setup' => fn() => update_option( 'woocommerce_feature_remote_logging_enabled', 'no' ), ), - 'tracking opted out' => array( + 'tracking opted out' => array( 'condition' => 'tracking opted out', 'setup' => fn() => add_filter( 'option_woocommerce_allow_tracking', fn() => 'no' ), ), - 'outdated version' => array( - 'condition' => 'outdated version', - 'setup' => function () { + 'high variant assignment' => array( + 'condition' => 'high variant assignment', + 'setup' => fn() => add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 15 ), + ), + 'outdated version' => array( + 'condition' => 'outdated version', + 'setup' => function () { $version = WC()->version; + // Next major version. (e.g. 9.0.1 -> 10.0.0). $next_version = implode( '.', array_map( @@ -112,28 +117,79 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { array_keys( explode( '.', $version ) ) ) ); - set_transient( RemoteLogger::WC_LATEST_VERSION_TRANSIENT, $next_version ); + + set_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT, $next_version, WEEK_IN_SECONDS ); }, - 'high variant assignment' => array( - 'condition' => 'high variant assignment', - 'setup' => fn() => add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 15 ), - ), ), ); } - /** - * @testdox Fetch latest WooCommerce version retries on API failure - */ - public function test_fetch_latest_woocommerce_version_retry() { - $this->setup_remote_logging_conditions( true ); - add_filter( 'plugins_api', fn() => new \WP_Error(), 10, 3 ); - for ( $i = 1; $i <= 4; $i++ ) { - $this->sut->is_remote_logging_allowed(); - $retry_count = get_transient( RemoteLogger::FETCH_LATEST_VERSION_RETRY ); - $this->assertEquals( min( $i, 3 ), $retry_count ); + /** + * @testdox should_current_version_be_logged method behaves correctly + * @dataProvider should_current_version_be_logged_provider + * + * @param string $current_version The current WooCommerce version. + * @param string $new_version The new WooCommerce version. + * @param string $transient_value The value of the transient. + * @param bool $expected The expected result. + */ + public function test_should_current_version_be_logged( $current_version, $new_version, $transient_value, $expected ) { + $wc_version = WC()->version; + WC()->version = $current_version; + + // Set up the transient. + if ( null !== $transient_value ) { + set_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT, $transient_value, WEEK_IN_SECONDS ); + } else { + delete_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); + + $this->setup_mock_plugin_updates( $new_version ); } + + $result = $this->invoke_private_method( $this->sut, 'should_current_version_be_logged', array() ); + $this->assertEquals( $expected, $result ); + + // Clean up. + delete_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); + + WC()->version = $wc_version; + } + + /** + * Data provider for test_should_current_version_be_logged. + */ + public function should_current_version_be_logged_provider() { + return array( + 'current version is latest (transient set)' => array( '9.2.0', '9.2.0', '9.2.0', true ), + 'current version is newer (transient set)' => array( '9.3.0', '9.2.0', '9.2.0', true ), + 'current version is older (transient set)' => array( '9.1.0', '9.2.0', '9.2.0', false ), + 'new version is null (transient set)' => array( '9.2.0', null, null, true ), + 'transient not set, current version is latest' => array( '9.2.0', '9.2.0', null, true ), + 'transient not set, current version is newer' => array( '9.3.0', '9.2.0', null, true ), + 'transient not set, current version is older' => array( '9.1.0', '9.2.0', null, false ), + 'transient not set, new version is null' => array( '9.2.0', null, null, true ), + ); + } + + /** + * @testdox fetch_new_woocommerce_version method returns correct version + */ + public function test_fetch_new_woocommerce_version() { + $this->setup_mock_plugin_updates( '9.3.0' ); + + $result = $this->invoke_private_method( $this->sut, 'fetch_new_woocommerce_version', array() ); + $this->assertEquals( '9.3.0', $result, 'The result should be the latest version when an update is available.' ); + } + + /** + * @testdox fetch_new_woocommerce_version method returns null when no update is available + */ + public function test_fetch_new_woocommerce_version_no_update() { + add_filter( 'pre_site_transient_update_plugins', fn() => array() ); + + $result = $this->invoke_private_method( $this->sut, 'fetch_new_woocommerce_version', array() ); + $this->assertNull( $result, 'The result should be null when no update is available.' ); } /** @@ -421,17 +477,26 @@ class RemoteLoggerTest extends \WC_Unit_Test_Case { update_option( 'woocommerce_feature_remote_logging_enabled', $enabled ? 'yes' : 'no' ); add_filter( 'option_woocommerce_allow_tracking', fn() => 'yes' ); add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 5 ); - add_filter( - 'plugins_api', - function ( $result, $action, $args ) use ( $enabled ) { - if ( 'plugin_information' === $action && 'woocommerce' === $args->slug ) { - return (object) array( 'version' => $enabled ? WC()->version : '9.0.0' ); - } - return $result; - }, - 10, - 3 + $this->setup_mock_plugin_updates( $enabled ? WC()->version : '9.0.0' ); + } + + + /** + * Set up mock plugin updates. + * + * @param string $new_version The new version of WooCommerce to simulate. + */ + private function setup_mock_plugin_updates( $new_version ) { + $update_plugins = (object) array( + 'response' => array( + WC_PLUGIN_BASENAME => (object) array( + 'new_version' => $new_version, + 'package' => 'https://downloads.wordpress.org/plugin/woocommerce.zip', + 'slug' => 'woocommerce', + ), + ), ); + add_filter( 'pre_site_transient_update_plugins', fn() => $update_plugins ); } /** From 502b4abe43e7565356bf95c2b8f824c9c8e62534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Rinc=C3=B3n?= Date: Fri, 30 Aug 2024 14:40:05 +0200 Subject: [PATCH 166/185] Fix increasing & decreasing sale price in product bulk edit (#50842) * Set the regular price when the `Change to:` price is left empty * Avoid fatal error when price is empty * Add changefile(s) from automation for the following project(s): woocommerce * Avoid setting the price to 0 when there wasn't a previous sale * Move the WC_Tests_Admin_Post_Types test to the appropiate folder so it's run * Add e2e test * Add e2e test * Add changefile(s) from automation for the following project(s): woocommerce * Add changefile(s) from automation for the following project(s): woocommerce * Fix lint errors * Fix lint errors * Fix test * Fix lint errors * Revert mv * Address increasing sale from 0 --------- Co-authored-by: github-actions --- ...-43149-fix-bulk-product-price-in-de-crease | 4 + .../admin/class-wc-admin-post-types.php | 3 +- .../tests/merchant/product-edit.spec.js | 116 ++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 plugins/woocommerce/changelog/50842-43149-fix-bulk-product-price-in-de-crease diff --git a/plugins/woocommerce/changelog/50842-43149-fix-bulk-product-price-in-de-crease b/plugins/woocommerce/changelog/50842-43149-fix-bulk-product-price-in-de-crease new file mode 100644 index 00000000000..affaea6bdf9 --- /dev/null +++ b/plugins/woocommerce/changelog/50842-43149-fix-bulk-product-price-in-de-crease @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Product bulk edit: fix increasing & decreasing sale price when there was no previous sale. \ No newline at end of file diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-post-types.php b/plugins/woocommerce/includes/admin/class-wc-admin-post-types.php index 741fda165cd..095893653ba 100644 --- a/plugins/woocommerce/includes/admin/class-wc-admin-post-types.php +++ b/plugins/woocommerce/includes/admin/class-wc-admin-post-types.php @@ -896,7 +896,8 @@ class WC_Admin_Post_Types { return false; } - $old_price = (float) $product->{"get_{$price_type}_price"}(); + $old_price = $product->{"get_{$price_type}_price"}(); + $old_price = '' === $old_price ? (float) $product->get_regular_price() : (float) $old_price; $price_changed = false; $change_price = absint( $request_data[ "change_{$price_type}_price" ] ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js index 89d18f069f5..e94595088b6 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js @@ -282,3 +282,119 @@ test( } ); } ); + +test( + 'can decrease the sale price if the product was not previously in sale when bulk editing products', + { tag: [ '@gutenberg', '@services' ] }, + async ( { page, products } ) => { + await page.goto( `wp-admin/edit.php?post_type=product` ); + + const salePriceDecrease = 10; + + await test.step( 'Update products with the "Sale > Decrease existing sale price" option', async () => { + await page.goto( `wp-admin/edit.php?post_type=product` ); + + for ( const product of products ) { + await page.getByLabel( `Select ${ product.name }` ).click(); + } + + await page + .locator( '#bulk-action-selector-top' ) + .selectOption( 'Edit' ); + await page.locator( '#doaction' ).click(); + + await page + .locator( 'select[name="change_sale_price"]' ) + .selectOption( + 'Decrease existing sale price by (fixed amount or %):' + ); + await page + .getByPlaceholder( 'Enter sale price ($)' ) + .fill( `${ salePriceDecrease }%` ); + + await page.getByRole( 'button', { name: 'Update' } ).click(); + } ); + + await test.step( 'Verify products have a sale price', async () => { + for ( const product of products ) { + await page.goto( `product/${ product.slug }` ); + + const expectedSalePrice = ( + product.regular_price * + ( 1 - salePriceDecrease / 100 ) + ).toFixed( 2 ); + + await expect + .soft( + await page + .locator( 'ins' ) + .getByText( `$${ expectedSalePrice }` ) + .count() + ) + .toBeGreaterThan( 0 ); + } + } ); + } +); + +test( + 'increasing the sale price from 0 does not change the sale price when bulk editing products', + { tag: [ '@gutenberg', '@services' ] }, + async ( { page, api } ) => { + let product; + await api + .post( 'products', { + id: 0, + name: `Product _${ Date.now() }`, + type: 'simple', + regular_price: '100', + sale_price: '0', + manage_stock: true, + stock_quantity: 10, + stock_status: 'instock', + } ) + .then( ( response ) => { + product = response.data; + } ); + + const salePriceIncrease = 10; + + await test.step( 'Update products with the "Sale > Increase existing sale price" option', async () => { + await page.goto( `wp-admin/edit.php?post_type=product` ); + + await page.getByLabel( `Select ${ product.name }` ).click(); + + await page + .locator( '#bulk-action-selector-top' ) + .selectOption( 'Edit' ); + await page.locator( '#doaction' ).click(); + + await page + .locator( 'select[name="change_sale_price"]' ) + .selectOption( + 'Increase existing sale price by (fixed amount or %):' + ); + + await page + .getByPlaceholder( 'Enter sale price ($)' ) + .fill( `${ salePriceIncrease }%` ); + + await page.getByRole( 'button', { name: 'Update' } ).click(); + } ); + + await test.step( 'Verify products have a sale price', async () => { + await page.goto( `product/${ product.slug }` ); + + const expectedSalePrice = '$0.00'; + + await expect + .soft( + await page + .locator( 'ins' ) + .getByText( expectedSalePrice ) + .count() + ) + .toBeGreaterThan( 0 ); + } ); + } +); From e589fa87e1c685ce3a2b769b1031f5d4fe166fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Fri, 30 Aug 2024 16:59:28 +0200 Subject: [PATCH 167/185] CYS: Mark several classes as internal (#51069) * CYS: Mark several classes as internal * Add changelog file --- plugins/woocommerce/changelog/fix-cys-internal-classes | 4 ++++ .../Admin/Features/OnboardingTasks/Tasks/CustomizeStore.php | 2 ++ plugins/woocommerce/src/Blocks/AI/Configuration.php | 2 ++ plugins/woocommerce/src/Blocks/AI/Connection.php | 2 ++ plugins/woocommerce/src/Blocks/AIContent/ContentProcessor.php | 2 ++ .../woocommerce/src/Blocks/AIContent/PatternsDictionary.php | 2 ++ plugins/woocommerce/src/Blocks/AIContent/PatternsHelper.php | 2 ++ plugins/woocommerce/src/Blocks/AIContent/UpdatePatterns.php | 2 ++ plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php | 2 ++ plugins/woocommerce/src/Blocks/Patterns/AIPatterns.php | 2 ++ plugins/woocommerce/src/Blocks/Patterns/PTKClient.php | 2 ++ plugins/woocommerce/src/Blocks/Patterns/PTKPatternsStore.php | 2 ++ plugins/woocommerce/src/Blocks/Patterns/PatternRegistry.php | 2 ++ 13 files changed, 28 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-cys-internal-classes diff --git a/plugins/woocommerce/changelog/fix-cys-internal-classes b/plugins/woocommerce/changelog/fix-cys-internal-classes new file mode 100644 index 00000000000..0bbe2f28b7d --- /dev/null +++ b/plugins/woocommerce/changelog/fix-cys-internal-classes @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Mark several Customize Your Store PHP classes as internal diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/CustomizeStore.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/CustomizeStore.php index fe6a2f28b7a..91fc334318f 100644 --- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/CustomizeStore.php +++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/CustomizeStore.php @@ -7,6 +7,8 @@ use WP_Post; /** * Customize Your Store Task + * + * @internal */ class CustomizeStore extends Task { /** diff --git a/plugins/woocommerce/src/Blocks/AI/Configuration.php b/plugins/woocommerce/src/Blocks/AI/Configuration.php index cd60cdd7f25..426a672db06 100644 --- a/plugins/woocommerce/src/Blocks/AI/Configuration.php +++ b/plugins/woocommerce/src/Blocks/AI/Configuration.php @@ -8,6 +8,8 @@ use Automattic\Jetpack\Connection\Utils; /** * Class Configuration + * + * @internal */ class Configuration { diff --git a/plugins/woocommerce/src/Blocks/AI/Connection.php b/plugins/woocommerce/src/Blocks/AI/Connection.php index cedd08b8cd2..0a20ddf10f8 100644 --- a/plugins/woocommerce/src/Blocks/AI/Connection.php +++ b/plugins/woocommerce/src/Blocks/AI/Connection.php @@ -10,6 +10,8 @@ use WpOrg\Requests\Requests; /** * Class Connection + * + * @internal */ class Connection { const TEXT_COMPLETION_API_URL = 'https://public-api.wordpress.com/wpcom/v2/text-completion'; diff --git a/plugins/woocommerce/src/Blocks/AIContent/ContentProcessor.php b/plugins/woocommerce/src/Blocks/AIContent/ContentProcessor.php index 55b202c0e3c..1f34077fb26 100644 --- a/plugins/woocommerce/src/Blocks/AIContent/ContentProcessor.php +++ b/plugins/woocommerce/src/Blocks/AIContent/ContentProcessor.php @@ -10,6 +10,8 @@ use WP_Error; * ContentProcessor class. * * Process images for content + * + * @internal */ class ContentProcessor { diff --git a/plugins/woocommerce/src/Blocks/AIContent/PatternsDictionary.php b/plugins/woocommerce/src/Blocks/AIContent/PatternsDictionary.php index cb87c48b8ea..9a881e47787 100644 --- a/plugins/woocommerce/src/Blocks/AIContent/PatternsDictionary.php +++ b/plugins/woocommerce/src/Blocks/AIContent/PatternsDictionary.php @@ -5,6 +5,8 @@ namespace Automattic\WooCommerce\Blocks\AIContent; /** * Patterns Dictionary class. + * + * @internal */ class PatternsDictionary { /** diff --git a/plugins/woocommerce/src/Blocks/AIContent/PatternsHelper.php b/plugins/woocommerce/src/Blocks/AIContent/PatternsHelper.php index d6eceadb97e..560d7ec831b 100644 --- a/plugins/woocommerce/src/Blocks/AIContent/PatternsHelper.php +++ b/plugins/woocommerce/src/Blocks/AIContent/PatternsHelper.php @@ -6,6 +6,8 @@ use WP_Error; /** * Patterns Helper class. + * + * @internal */ class PatternsHelper { /** diff --git a/plugins/woocommerce/src/Blocks/AIContent/UpdatePatterns.php b/plugins/woocommerce/src/Blocks/AIContent/UpdatePatterns.php index d9e792e85eb..d2e0228ca5f 100644 --- a/plugins/woocommerce/src/Blocks/AIContent/UpdatePatterns.php +++ b/plugins/woocommerce/src/Blocks/AIContent/UpdatePatterns.php @@ -7,6 +7,8 @@ use WP_Error; /** * Pattern Images class. + * + * @internal */ class UpdatePatterns { diff --git a/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php b/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php index 20e0549f8e3..571cb08029e 100644 --- a/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php +++ b/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php @@ -6,6 +6,8 @@ use Automattic\WooCommerce\Blocks\AI\Connection; use WP_Error; /** * Pattern Images class. + * + * @internal */ class UpdateProducts { diff --git a/plugins/woocommerce/src/Blocks/Patterns/AIPatterns.php b/plugins/woocommerce/src/Blocks/Patterns/AIPatterns.php index 8bcf093fd1f..6982fad05a7 100644 --- a/plugins/woocommerce/src/Blocks/Patterns/AIPatterns.php +++ b/plugins/woocommerce/src/Blocks/Patterns/AIPatterns.php @@ -8,6 +8,8 @@ use Automattic\WooCommerce\Blocks\Images\Pexels; /** * AIPatterns class. + * + * @internal */ class AIPatterns { const PATTERNS_AI_DATA_POST_TYPE = 'patterns_ai_data'; diff --git a/plugins/woocommerce/src/Blocks/Patterns/PTKClient.php b/plugins/woocommerce/src/Blocks/Patterns/PTKClient.php index e319c22ffed..2b86b3c857c 100644 --- a/plugins/woocommerce/src/Blocks/Patterns/PTKClient.php +++ b/plugins/woocommerce/src/Blocks/Patterns/PTKClient.php @@ -5,6 +5,8 @@ use WP_Error; /** * PatternsToolkit class. + * + * @internal */ class PTKClient { /** diff --git a/plugins/woocommerce/src/Blocks/Patterns/PTKPatternsStore.php b/plugins/woocommerce/src/Blocks/Patterns/PTKPatternsStore.php index 2b24e1a9657..1ce873b39f8 100644 --- a/plugins/woocommerce/src/Blocks/Patterns/PTKPatternsStore.php +++ b/plugins/woocommerce/src/Blocks/Patterns/PTKPatternsStore.php @@ -7,6 +7,8 @@ use WP_Upgrader; /** * PTKPatterns class. + * + * @internal */ class PTKPatternsStore { const TRANSIENT_NAME = 'ptk_patterns'; diff --git a/plugins/woocommerce/src/Blocks/Patterns/PatternRegistry.php b/plugins/woocommerce/src/Blocks/Patterns/PatternRegistry.php index 9a79a95cc5b..3af03be5200 100644 --- a/plugins/woocommerce/src/Blocks/Patterns/PatternRegistry.php +++ b/plugins/woocommerce/src/Blocks/Patterns/PatternRegistry.php @@ -5,6 +5,8 @@ use Automattic\WooCommerce\Admin\Features\Features; /** * PatternRegistry class. + * + * @internal */ class PatternRegistry { const SLUG_REGEX = '/^[A-z0-9\/_-]+$/'; From 2890e16c86eff1b8c70c64fbd6547a78a6dfc281 Mon Sep 17 00:00:00 2001 From: louwie17 Date: Fri, 30 Aug 2024 18:27:10 +0200 Subject: [PATCH 168/185] Add product data views list to experimental product data views page (#51008) * Add products data views list * Add navigation on the left * Update edit site package * Fix styling * Add changelog * Add wp/icons package to syncpack exception list * Delete some unused stuff and address types * Add changelog * Remove un needed css * Remove dependency on edit-site package * Fix custom status filters * Make sure page size works with view config * Remove use of canvasMode and navigation context as it is not needed * Remove wordpress/dom from syncpack --- .syncpackrc | 4 +- .../changelog/add-product_data_views_list | 4 + packages/js/product-editor/package.json | 3 +- .../src/products-app/constants.ts | 8 + .../product-editor/src/products-app/index.tsx | 6 +- .../src/products-app/layout.tsx | 118 ++ .../src/products-app/product-list/index.tsx | 343 +++++ .../src/products-app/router.tsx | 68 + .../sidebar-dataviews/dataview-item.tsx | 110 ++ .../sidebar-dataviews/default-views.ts | 179 +++ .../products-app/sidebar-dataviews/index.tsx | 55 + .../products-app/sidebar-dataviews/style.scss | 19 + .../sidebar-navigation-item/index.tsx | 88 ++ .../sidebar-navigation-screen/index.tsx | 136 ++ .../sidebar-button.tsx | 18 + .../src/products-app/sidebar/index.tsx | 31 + .../src/products-app/site-hub/index.tsx | 114 ++ .../src/products-app/site-hub/site-icon.tsx | 56 + packages/js/product-editor/src/products.scss | 7 +- packages/js/product-editor/typings/index.d.ts | 22 + plugins/woocommerce-admin/webpack.config.js | 6 + .../changelog/add-product_data_views_list | 4 + pnpm-lock.yaml | 1242 ++++++++--------- 23 files changed, 1988 insertions(+), 653 deletions(-) create mode 100644 packages/js/product-editor/changelog/add-product_data_views_list create mode 100644 packages/js/product-editor/src/products-app/constants.ts create mode 100644 packages/js/product-editor/src/products-app/layout.tsx create mode 100644 packages/js/product-editor/src/products-app/product-list/index.tsx create mode 100644 packages/js/product-editor/src/products-app/router.tsx create mode 100644 packages/js/product-editor/src/products-app/sidebar-dataviews/dataview-item.tsx create mode 100644 packages/js/product-editor/src/products-app/sidebar-dataviews/default-views.ts create mode 100644 packages/js/product-editor/src/products-app/sidebar-dataviews/index.tsx create mode 100644 packages/js/product-editor/src/products-app/sidebar-dataviews/style.scss create mode 100644 packages/js/product-editor/src/products-app/sidebar-navigation-item/index.tsx create mode 100644 packages/js/product-editor/src/products-app/sidebar-navigation-screen/index.tsx create mode 100644 packages/js/product-editor/src/products-app/sidebar-navigation-screen/sidebar-button.tsx create mode 100644 packages/js/product-editor/src/products-app/sidebar/index.tsx create mode 100644 packages/js/product-editor/src/products-app/site-hub/index.tsx create mode 100644 packages/js/product-editor/src/products-app/site-hub/site-icon.tsx create mode 100644 plugins/woocommerce/changelog/add-product_data_views_list diff --git a/.syncpackrc b/.syncpackrc index 7a4664d5842..ce95ab63970 100644 --- a/.syncpackrc +++ b/.syncpackrc @@ -201,7 +201,9 @@ "@wordpress/interface", "@wordpress/router", "@wordpress/edit-site", - "@wordpress/private-apis" + "@wordpress/private-apis", + "@wordpress/dataviews", + "@wordpress/icons" ], "packages": [ "@woocommerce/block-templates", diff --git a/packages/js/product-editor/changelog/add-product_data_views_list b/packages/js/product-editor/changelog/add-product_data_views_list new file mode 100644 index 00000000000..548ca3eb055 --- /dev/null +++ b/packages/js/product-editor/changelog/add-product_data_views_list @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add sidebar and dataviews list to the experimental dataviews products page. diff --git a/packages/js/product-editor/package.json b/packages/js/product-editor/package.json index ba2ec86f116..52ec6eacb88 100644 --- a/packages/js/product-editor/package.json +++ b/packages/js/product-editor/package.json @@ -56,6 +56,7 @@ "@wordpress/compose": "wp-6.0", "@wordpress/core-data": "wp-6.0", "@wordpress/data": "wp-6.0", + "@wordpress/dataviews": "^4.2.0", "@wordpress/date": "wp-6.0", "@wordpress/deprecated": "wp-6.0", "@wordpress/edit-post": "wp-6.0", @@ -64,7 +65,7 @@ "@wordpress/hooks": "wp-6.0", "@wordpress/html-entities": "wp-6.0", "@wordpress/i18n": "wp-6.0", - "@wordpress/icons": "wp-6.0", + "@wordpress/icons": "10.6.0", "@wordpress/interface": "wp-6.0", "@wordpress/keyboard-shortcuts": "wp-6.0", "@wordpress/keycodes": "wp-6.0", diff --git a/packages/js/product-editor/src/products-app/constants.ts b/packages/js/product-editor/src/products-app/constants.ts new file mode 100644 index 00000000000..8c2b1b338f9 --- /dev/null +++ b/packages/js/product-editor/src/products-app/constants.ts @@ -0,0 +1,8 @@ +export const LAYOUT_GRID = 'grid'; +export const LAYOUT_TABLE = 'table'; +export const LAYOUT_LIST = 'list'; + +export const OPERATOR_IS = 'is'; +export const OPERATOR_IS_NOT = 'isNot'; +export const OPERATOR_IS_ANY = 'isAny'; +export const OPERATOR_IS_NONE = 'isNone'; diff --git a/packages/js/product-editor/src/products-app/index.tsx b/packages/js/product-editor/src/products-app/index.tsx index 69bef7fb2af..44c15e41dfa 100644 --- a/packages/js/product-editor/src/products-app/index.tsx +++ b/packages/js/product-editor/src/products-app/index.tsx @@ -13,12 +13,16 @@ import { * Internal dependencies */ import { unlock } from '../lock-unlock'; +import useLayoutAreas from './router'; +import { Layout } from './layout'; const { RouterProvider } = unlock( routerPrivateApis ); const { GlobalStylesProvider } = unlock( editorPrivateApis ); function ProductsLayout() { - return
        Initial Products Layout
        ; + // This ensures the edited entity id and type are initialized properly. + const route = useLayoutAreas(); + return ; } export function ProductsApp() { diff --git a/packages/js/product-editor/src/products-app/layout.tsx b/packages/js/product-editor/src/products-app/layout.tsx new file mode 100644 index 00000000000..fe084ebf646 --- /dev/null +++ b/packages/js/product-editor/src/products-app/layout.tsx @@ -0,0 +1,118 @@ +/** + * External dependencies + */ +import { createElement, Fragment, useRef } from '@wordpress/element'; +import { + useViewportMatch, + useResizeObserver, + useReducedMotion, +} from '@wordpress/compose'; +import { __ } from '@wordpress/i18n'; +import { + // @ts-expect-error missing type. + EditorSnackbars, + // @ts-expect-error missing type. + privateApis as editorPrivateApis, +} from '@wordpress/editor'; +// eslint-disable-next-line @woocommerce/dependency-group +import { + // @ts-expect-error missing type. + __unstableMotion as motion, + // @ts-expect-error missing type. + __unstableAnimatePresence as AnimatePresence, +} from '@wordpress/components'; + +/** + * Internal dependencies + */ +import SidebarContent from './sidebar'; +import SiteHub from './site-hub'; +import { Route } from './router'; +import { unlock } from '../lock-unlock'; + +const { NavigableRegion } = unlock( editorPrivateApis ); + +const ANIMATION_DURATION = 0.3; + +type LayoutProps = { + route: Route; +}; + +export function Layout( { route }: LayoutProps ) { + const [ fullResizer ] = useResizeObserver(); + const toggleRef = useRef< HTMLAnchorElement >( null ); + const isMobileViewport = useViewportMatch( 'medium', '<' ); + const disableMotion = useReducedMotion(); + + const { key: routeKey, areas, widths } = route; + + return ( + <> + { fullResizer } +
        +
        + { /* + The NavigableRegion must always be rendered and not use + `inert` otherwise `useNavigateRegions` will fail. + */ } + { ( ! isMobileViewport || ! areas.mobile ) && ( + + + + + + { areas.sidebar } + + + + + ) } + + + + { ! isMobileViewport && areas.content && ( +
        + { areas.content } +
        + ) } + + { ! isMobileViewport && areas.edit && ( +
        + { areas.edit } +
        + ) } +
        +
        + + ); +} diff --git a/packages/js/product-editor/src/products-app/product-list/index.tsx b/packages/js/product-editor/src/products-app/product-list/index.tsx new file mode 100644 index 00000000000..6a0988b2448 --- /dev/null +++ b/packages/js/product-editor/src/products-app/product-list/index.tsx @@ -0,0 +1,343 @@ +/** + * External dependencies + */ +import { Action, DataViews, View } from '@wordpress/dataviews'; +import { + createElement, + useState, + useMemo, + useCallback, + useEffect, +} from '@wordpress/element'; +import { Product, ProductQuery } from '@woocommerce/data'; +import { drawerRight } from '@wordpress/icons'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { __ } from '@wordpress/i18n'; +import { useSelect } from '@wordpress/data'; +import classNames from 'classnames'; +import { + // @ts-expect-error missing types. + __experimentalHeading as Heading, + // @ts-expect-error missing types. + __experimentalText as Text, + // @ts-expect-error missing types. + __experimentalHStack as HStack, + // @ts-expect-error missing types. + __experimentalVStack as VStack, + FlexItem, + Button, +} from '@wordpress/components'; +// @ts-expect-error missing type. +// eslint-disable-next-line @woocommerce/dependency-group +import { privateApis as editorPrivateApis } from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { + useDefaultViews, + defaultLayouts, +} from '../sidebar-dataviews/default-views'; +import { LAYOUT_LIST, OPERATOR_IS } from '../constants'; + +const { NavigableRegion } = unlock( editorPrivateApis ); +const { useHistory, useLocation } = unlock( routerPrivateApis ); + +const STATUSES = [ + { value: 'draft', label: __( 'Draft', 'woocommerce' ) }, + { value: 'future', label: __( 'Scheduled', 'woocommerce' ) }, + { value: 'private', label: __( 'Private', 'woocommerce' ) }, + { value: 'publish', label: __( 'Published', 'woocommerce' ) }, + { value: 'trash', label: __( 'Trash', 'woocommerce' ) }, +]; + +/** + * TODO: auto convert some of the product editor blocks ( from the blocks directory ) to this format. + * The edit function should work relatively well with the edit from the blocks, the only difference is that the blocks rely on getEntityProp to get the value + */ +const fields = [ + { + id: 'name', + label: __( 'Name', 'woocommerce' ), + enableHiding: false, + type: 'text', + render: function nameRender( { item }: { item: Product } ) { + return item.name; + }, + }, + { + id: 'sku', + label: __( 'SKU', 'woocommerce' ), + enableHiding: false, + enableSorting: false, + render: ( { item }: { item: Product } ) => { + return item.sku; + }, + }, + { + id: 'date', + label: __( 'Date', 'woocommerce' ), + render: ( { item }: { item: Product } ) => { + return ; + }, + }, + { + label: __( 'Status', 'woocommerce' ), + id: 'status', + getValue: ( { item }: { item: Product } ) => + STATUSES.find( ( { value } ) => value === item.status )?.label ?? + item.status, + elements: STATUSES, + filterBy: { + operators: [ OPERATOR_IS ], + }, + enableSorting: false, + }, +]; + +export type ProductListProps = { + subTitle?: string; + className?: string; + hideTitleFromUI?: boolean; + postType?: string; +}; + +const PAGE_SIZE = 25; +const EMPTY_ARRAY: Product[] = []; +const EMPTY_ACTIONS_ARRAY: Action< Product >[] = []; + +const getDefaultView = ( + defaultViews: Array< { slug: string; view: View } >, + activeView: string +) => { + return defaultViews.find( ( { slug } ) => slug === activeView )?.view; +}; + +/** + * This function abstracts working with default & custom views by + * providing a [ state, setState ] tuple based on the URL parameters. + * + * Consumers use the provided tuple to work with state + * and don't have to deal with the specifics of default & custom views. + * + * @param {string} postType Post type to retrieve default views for. + * @return {Array} The [ state, setState ] tuple. + */ +function useView( + postType: string +): [ View, ( view: View ) => void, ( view: View ) => void ] { + const { + params: { activeView = 'all', isCustom = 'false', layout }, + } = useLocation(); + const history = useHistory(); + + const defaultViews = useDefaultViews( { postType } ); + const [ view, setView ] = useState< View >( () => { + const initialView = getDefaultView( defaultViews, activeView ) ?? { + type: layout ?? LAYOUT_LIST, + }; + + const type = layout ?? initialView.type; + return { + ...initialView, + type, + }; + } ); + + const setViewWithUrlUpdate = useCallback( + ( newView: View ) => { + const { params } = history.getLocationWithParams(); + + if ( newView.type === LAYOUT_LIST && ! params?.layout ) { + // Skip updating the layout URL param if + // it is not present and the newView.type is LAYOUT_LIST. + } else if ( newView.type !== params?.layout ) { + history.push( { + ...params, + layout: newView.type, + } ); + } + + setView( newView ); + }, + [ history, isCustom ] + ); + + // When layout URL param changes, update the view type + // without affecting any other config. + useEffect( () => { + setView( ( prevView ) => ( { + ...prevView, + type: layout ?? LAYOUT_LIST, + } ) ); + }, [ layout ] ); + + // When activeView or isCustom URL parameters change, reset the view. + useEffect( () => { + const newView = getDefaultView( defaultViews, activeView ); + + if ( newView ) { + const type = layout ?? newView.type; + setView( { + ...newView, + type, + } ); + } + }, [ activeView, isCustom, layout, defaultViews ] ); + + return [ view, setViewWithUrlUpdate, setViewWithUrlUpdate ]; +} + +function getItemId( item: Product ) { + return item.id.toString(); +} + +export default function ProductList( { + subTitle, + className, + hideTitleFromUI = false, +}: ProductListProps ) { + const history = useHistory(); + const location = useLocation(); + const { + postId, + quickEdit = false, + postType = 'product', + isCustom, + activeView = 'all', + } = location.params; + const [ selection, setSelection ] = useState( [ postId ] ); + const [ view, setView ] = useView( postType ); + + const queryParams = useMemo( () => { + const filters: Partial< ProductQuery > = {}; + view.filters?.forEach( ( filter ) => { + if ( filter.field === 'status' ) { + filters.status = Array.isArray( filter.value ) + ? filter.value.join( ',' ) + : filter.value; + } + } ); + const orderby = + view.sort?.field === 'name' ? 'title' : view.sort?.field; + + return { + per_page: view.perPage, + page: view.page, + order: view.sort?.direction, + orderby, + search: view.search, + ...filters, + }; + }, [ location.params, view ] ); + + const onChangeSelection = useCallback( + ( items ) => { + setSelection( items ); + history.push( { + ...location.params, + postId: items.join( ',' ), + } ); + }, + [ history, location.params, view?.type ] + ); + + // TODO: Use the Woo data store to get all the products, as this doesn't contain all the product data. + const { records, totalCount, isLoading } = useSelect( + ( select ) => { + const { getProducts, getProductsTotalCount, isResolving } = + select( 'wc/admin/products' ); + return { + records: getProducts( queryParams ) as Product[], + totalCount: getProductsTotalCount( queryParams ) as number, + isLoading: isResolving( 'getProducts', [ queryParams ] ), + }; + }, + [ queryParams ] + ); + + const paginationInfo = useMemo( + () => ( { + totalItems: totalCount, + totalPages: Math.ceil( totalCount / ( view.perPage || PAGE_SIZE ) ), + } ), + [ totalCount, view.perPage ] + ); + + const classes = classNames( 'edit-site-page', className ); + + return ( + +
        + { ! hideTitleFromUI && ( + + + + { __( 'Products', 'woocommerce' ) } + + + { /* { actions } */ } + + + { subTitle && ( + + { subTitle } + + ) } + + ) } + { + history.push( { + ...location.params, + quickEdit: quickEdit ? undefined : true, + } ); + } } + /> + } + /> +
        +
        + ); +} diff --git a/packages/js/product-editor/src/products-app/router.tsx b/packages/js/product-editor/src/products-app/router.tsx new file mode 100644 index 00000000000..3acbc510aba --- /dev/null +++ b/packages/js/product-editor/src/products-app/router.tsx @@ -0,0 +1,68 @@ +/** + * External dependencies + */ +import { createElement } from '@wordpress/element'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; + +/** + * Internal dependencies + */ +import { unlock } from '../lock-unlock'; +import ProductList from './product-list'; +import DataViewsSidebarContent from './sidebar-dataviews'; +import SidebarNavigationScreen from './sidebar-navigation-screen'; + +const { useLocation } = unlock( routerPrivateApis ); + +export type Route = { + key: string; + areas: { + sidebar: React.JSX.Element | React.FunctionComponent; + content?: React.JSX.Element | React.FunctionComponent; + edit?: React.JSX.Element | React.FunctionComponent; + mobile?: React.JSX.Element | React.FunctionComponent | boolean; + preview?: boolean; + }; + widths?: { + content?: number; + edit?: number; + sidebar?: number; + }; +}; + +export default function useLayoutAreas() { + const { params = {} } = useLocation(); + const { postType = 'product', layout = 'table', canvas } = params; + // Products list. + if ( [ 'product' ].includes( postType ) ) { + const isListLayout = layout === 'list' || ! layout; + return { + key: 'products-list', + areas: { + sidebar: ( + } + /> + ), + content: , + preview: false, + mobile: , + }, + widths: { + content: isListLayout ? 380 : undefined, + }, + }; + } + + // Fallback shows the home page preview + return { + key: 'default', + areas: { + sidebar: () => null, + preview: false, + mobile: canvas === 'edit', + }, + }; +} diff --git a/packages/js/product-editor/src/products-app/sidebar-dataviews/dataview-item.tsx b/packages/js/product-editor/src/products-app/sidebar-dataviews/dataview-item.tsx new file mode 100644 index 00000000000..03a4f8cee85 --- /dev/null +++ b/packages/js/product-editor/src/products-app/sidebar-dataviews/dataview-item.tsx @@ -0,0 +1,110 @@ +/** + * External dependencies + */ +import { createElement } from '@wordpress/element'; +import classNames from 'classnames'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { addQueryArgs, getQueryArgs, removeQueryArgs } from '@wordpress/url'; +import { VIEW_LAYOUTS } from '@wordpress/dataviews'; +// @ts-expect-error missing type. +// eslint-disable-next-line @woocommerce/dependency-group +import { __experimentalHStack as HStack } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import SidebarNavigationItem from '../sidebar-navigation-item'; +import { unlock } from '../../lock-unlock'; + +const { useHistory, useLocation } = unlock( routerPrivateApis ); + +type DataViewItemProps = { + title: string; + slug: string; + customViewId?: string; + type: string; + icon: React.JSX.Element; + isActive: boolean; + isCustom: boolean; + suffix?: string; +}; + +function useLink( + params: Record< string, string | undefined >, + state?: Record< string, string | undefined >, + shouldReplace = false +) { + const history = useHistory(); + function onClick( event: Event ) { + event?.preventDefault(); + + if ( shouldReplace ) { + history.replace( params, state ); + } else { + history.push( params, state ); + } + } + + const currentArgs = getQueryArgs( window.location.href ); + const currentUrlWithoutArgs = removeQueryArgs( + window.location.href, + ...Object.keys( currentArgs ) + ); + + const newUrl = addQueryArgs( currentUrlWithoutArgs, params ); + + return { + href: newUrl, + onClick, + }; +} + +export default function DataViewItem( { + title, + slug, + customViewId, + type, + icon, + isActive, + isCustom, + suffix, +}: DataViewItemProps ) { + const { + params: { postType, page }, + } = useLocation(); + + const iconToUse = + icon || VIEW_LAYOUTS.find( ( v ) => v.type === type )?.icon; + + let activeView: undefined | string = isCustom ? customViewId : slug; + if ( activeView === 'all' ) { + activeView = undefined; + } + const linkInfo = useLink( { + page, + postType, + layout: type, + activeView, + isCustom: isCustom ? 'true' : undefined, + } ); + return ( + + + { title } + + { suffix } + + ); +} diff --git a/packages/js/product-editor/src/products-app/sidebar-dataviews/default-views.ts b/packages/js/product-editor/src/products-app/sidebar-dataviews/default-views.ts new file mode 100644 index 00000000000..816477363f3 --- /dev/null +++ b/packages/js/product-editor/src/products-app/sidebar-dataviews/default-views.ts @@ -0,0 +1,179 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { useMemo } from '@wordpress/element'; +import { + trash, + pages, + drafts, + published, + scheduled, + notAllowed, +} from '@wordpress/icons'; +import type { ColumnStyle, ViewTable } from '@wordpress/dataviews'; + +/** + * Internal dependencies + */ +import { + LAYOUT_LIST, + LAYOUT_TABLE, + LAYOUT_GRID, + OPERATOR_IS, +} from '../constants'; + +export const defaultLayouts: Record< + string, + { + layout: { + primaryField: string; + mediaField?: string; + styles?: Record< string, ColumnStyle >; + }; + } +> = { + [ LAYOUT_TABLE ]: { + layout: { + primaryField: 'name', + styles: { + name: { + maxWidth: 300, + }, + }, + }, + }, + [ LAYOUT_GRID ]: { + layout: { + mediaField: 'featured-image', + primaryField: 'name', + }, + }, + [ LAYOUT_LIST ]: { + layout: { + primaryField: 'name', + mediaField: 'featured-image', + }, + }, +}; + +const DEFAULT_POST_BASE: Omit< ViewTable, 'view' | 'title' | 'slug' | 'icon' > = + { + type: LAYOUT_TABLE, + search: '', + filters: [], + page: 1, + perPage: 20, + sort: { + field: 'date', + direction: 'desc', + }, + fields: [ 'name', 'sku', 'status', 'date' ], + layout: defaultLayouts[ LAYOUT_LIST ].layout, + }; + +export function useDefaultViews( { postType }: { postType: string } ): Array< { + title: string; + slug: string; + icon: React.JSX.Element; + view: ViewTable; +} > { + const labels = useSelect( + ( select ) => { + const { getPostType } = select( coreStore ); + const postTypeData: { labels?: Record< string, string > } = + getPostType( postType ); + return postTypeData?.labels; + }, + [ postType ] + ); + return useMemo( () => { + return [ + { + title: labels?.all_items || __( 'All items', 'woocommerce' ), + slug: 'all', + icon: pages, + view: { ...DEFAULT_POST_BASE }, + }, + { + title: __( 'Published', 'woocommerce' ), + slug: 'published', + icon: published, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS, + value: 'publish', + }, + ], + }, + }, + { + title: __( 'Scheduled', 'woocommerce' ), + slug: 'future', + icon: scheduled, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS, + value: 'future', + }, + ], + }, + }, + { + title: __( 'Drafts', 'woocommerce' ), + slug: 'drafts', + icon: drafts, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS, + value: 'draft', + }, + ], + }, + }, + { + title: __( 'Private', 'woocommerce' ), + slug: 'private', + icon: notAllowed, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS, + value: 'private', + }, + ], + }, + }, + { + title: __( 'Trash', 'woocommerce' ), + slug: 'trash', + icon: trash, + view: { + ...DEFAULT_POST_BASE, + type: LAYOUT_TABLE, + layout: defaultLayouts[ LAYOUT_TABLE ].layout, + filters: [ + { + field: 'status', + operator: OPERATOR_IS, + value: 'trash', + }, + ], + }, + }, + ]; + }, [ labels ] ); +} diff --git a/packages/js/product-editor/src/products-app/sidebar-dataviews/index.tsx b/packages/js/product-editor/src/products-app/sidebar-dataviews/index.tsx new file mode 100644 index 00000000000..245675bfcf3 --- /dev/null +++ b/packages/js/product-editor/src/products-app/sidebar-dataviews/index.tsx @@ -0,0 +1,55 @@ +/** + * External dependencies + */ +import { createElement, Fragment } from '@wordpress/element'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; +// @ts-expect-error missing type. +// eslint-disable-next-line @wordpress/no-unsafe-wp-apis, @woocommerce/dependency-group +import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import DataViewItem from './dataview-item'; +import { useDefaultViews } from './default-views'; + +const { useLocation } = unlock( routerPrivateApis ); + +export default function DataViewsSidebarContent() { + const { + params: { + postType = 'product', + activeView = 'all', + isCustom = 'false', + }, + } = useLocation(); + const defaultViews = useDefaultViews( { postType } ); + if ( ! postType ) { + return null; + } + const isCustomBoolean = isCustom === 'true'; + + return ( + <> + + { defaultViews.map( ( dataview ) => { + return ( + + ); + } ) } + + + ); +} diff --git a/packages/js/product-editor/src/products-app/sidebar-dataviews/style.scss b/packages/js/product-editor/src/products-app/sidebar-dataviews/style.scss new file mode 100644 index 00000000000..d3744634f6a --- /dev/null +++ b/packages/js/product-editor/src/products-app/sidebar-dataviews/style.scss @@ -0,0 +1,19 @@ +.edit-site-sidebar-navigation-screen__title-icon { + position: sticky; + top: 0; + background: $gray-900; + padding-top: $grid-unit-60; + margin-bottom: $grid-unit-10; + padding-bottom: $grid-unit-10; +} + +.edit-site-sidebar-button { + color: #e0e0e0; + flex-shrink: 0; +} + +.edit-site-sidebar-navigation-screen__title { + flex-grow: 1; + overflow-wrap: break-word; + padding: 2px 0 0 +} diff --git a/packages/js/product-editor/src/products-app/sidebar-navigation-item/index.tsx b/packages/js/product-editor/src/products-app/sidebar-navigation-item/index.tsx new file mode 100644 index 00000000000..57f8c23657c --- /dev/null +++ b/packages/js/product-editor/src/products-app/sidebar-navigation-item/index.tsx @@ -0,0 +1,88 @@ +/** + * External dependencies + */ +import { isRTL } from '@wordpress/i18n'; +import { chevronRightSmall, chevronLeftSmall, Icon } from '@wordpress/icons'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; +import classNames from 'classnames'; +import { createElement } from '@wordpress/element'; +import { + // @ts-expect-error missing type. + __experimentalItem as Item, + // @ts-expect-error missing type. + __experimentalHStack as HStack, + FlexBlock, +} from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; + +const { useHistory } = unlock( routerPrivateApis ); + +type SidebarNavigationItemProps = { + className?: string; + icon?: React.JSX.Element; + suffix?: string; + withChevron?: boolean; + uid?: string; + params?: Record< string, string >; + onClick?: ( e: Event ) => void; + children: React.ReactNode; +}; + +export default function SidebarNavigationItem( { + className, + icon, + withChevron = false, + suffix, + uid, + params, + onClick, + children, + ...props +}: SidebarNavigationItemProps ) { + const history = useHistory(); + // If there is no custom click handler, create one that navigates to `params`. + function handleClick( e: Event ) { + if ( onClick ) { + onClick( e ); + } else if ( params ) { + e.preventDefault(); + history.push( params ); + } + } + + return ( + + + { icon && ( + + ) } + { children } + { withChevron && ( + + ) } + { ! withChevron && suffix } + + + ); +} diff --git a/packages/js/product-editor/src/products-app/sidebar-navigation-screen/index.tsx b/packages/js/product-editor/src/products-app/sidebar-navigation-screen/index.tsx new file mode 100644 index 00000000000..03a669c3ea2 --- /dev/null +++ b/packages/js/product-editor/src/products-app/sidebar-navigation-screen/index.tsx @@ -0,0 +1,136 @@ +/** + * External dependencies + */ + +import { isRTL, __ } from '@wordpress/i18n'; +import classNames from 'classnames'; +import { chevronRight, chevronLeft } from '@wordpress/icons'; +import { useSelect } from '@wordpress/data'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { createElement, Fragment } from '@wordpress/element'; +import { + // @ts-expect-error missing type. + __experimentalHStack as HStack, + // @ts-expect-error missing type. + __experimentalHeading as Heading, + // @ts-expect-error missing type. + __experimentalVStack as VStack, +} from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import SidebarButton from './sidebar-button'; + +const { useHistory, useLocation } = unlock( routerPrivateApis ); + +type SidebarNavigationScreenProps = { + isRoot?: boolean; + title: string; + actions?: React.JSX.Element; + meta?: string; + content: React.JSX.Element; + footer?: string; + description?: string; + backPath?: string; +}; + +export default function SidebarNavigationScreen( { + isRoot, + title, + actions, + meta, + content, + footer, + description, + backPath: backPathProp, +}: SidebarNavigationScreenProps ) { + const { dashboardLink, dashboardLinkText } = useSelect( ( select ) => { + const { getSettings } = unlock( select( 'core/edit-site' ) ); + return { + dashboardLink: getSettings().__experimentalDashboardLink, + dashboardLinkText: getSettings().__experimentalDashboardLinkText, + }; + }, [] ); + const location = useLocation(); + const history = useHistory(); + const backPath = backPathProp ?? location.state?.backPath; + const icon = isRTL() ? chevronRight : chevronLeft; + + return ( + <> + + + { ! isRoot && ( + { + history.push( backPath ); + } } + icon={ icon } + label={ __( 'Back', 'woocommerce' ) } + showTooltip={ false } + /> + ) } + { isRoot && ( + + ) } + + { title } + + { actions && ( +
        + { actions } +
        + ) } +
        + { meta && ( + <> +
        + { meta } +
        + + ) } + +
        + { description && ( +

        + { description } +

        + ) } + { content } +
        +
        + { footer && ( +
        + { footer } +
        + ) } + + ); +} diff --git a/packages/js/product-editor/src/products-app/sidebar-navigation-screen/sidebar-button.tsx b/packages/js/product-editor/src/products-app/sidebar-navigation-screen/sidebar-button.tsx new file mode 100644 index 00000000000..6033e202bf6 --- /dev/null +++ b/packages/js/product-editor/src/products-app/sidebar-navigation-screen/sidebar-button.tsx @@ -0,0 +1,18 @@ +/** + * External dependencies + */ +import { createElement } from '@wordpress/element'; +import { Button } from '@wordpress/components'; +import classNames from 'classnames'; + +export default function SidebarButton( props: Button.Props ) { + return ( + + + + +
        + +
        +
        + + + ); + } + ) +); + +export default SiteHub; diff --git a/packages/js/product-editor/src/products-app/site-hub/site-icon.tsx b/packages/js/product-editor/src/products-app/site-hub/site-icon.tsx new file mode 100644 index 00000000000..754dd6e39fc --- /dev/null +++ b/packages/js/product-editor/src/products-app/site-hub/site-icon.tsx @@ -0,0 +1,56 @@ +/** + * External dependencies + */ +import { createElement } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; +import { Icon } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { wordpress } from '@wordpress/icons'; +import { store as coreDataStore } from '@wordpress/core-data'; +import classNames from 'classnames'; + +type SiteIconProps = { + className: string; +}; + +function SiteIcon( { className }: SiteIconProps ) { + const { isRequestingSite, siteIconUrl } = useSelect( ( select ) => { + const { getEntityRecord } = select( coreDataStore ); + const siteData: { site_icon_url?: string } = getEntityRecord( + 'root', + '__unstableBase', + undefined + ); + + return { + isRequestingSite: ! siteData, + siteIconUrl: siteData?.site_icon_url, + }; + }, [] ); + + if ( isRequestingSite && ! siteIconUrl ) { + return
        ; + } + + const icon = siteIconUrl ? ( + { + ) : ( + + ); + + return ( +
        + { icon } +
        + ); +} + +export default SiteIcon; diff --git a/packages/js/product-editor/src/products.scss b/packages/js/product-editor/src/products.scss index 9a1199c1c33..7aaa6b290a4 100644 --- a/packages/js/product-editor/src/products.scss +++ b/packages/js/product-editor/src/products.scss @@ -4,11 +4,12 @@ .woocommerce_page_woocommerce-products-dashboard #adminmenumain { display: none; } + .woocommerce_page_woocommerce-products-dashboard #wpcontent { margin-left: 0; } -body.woocommerce_page_woocommerce-products-dashboard - #woocommerce-products-dashboard { + +body.woocommerce_page_woocommerce-products-dashboard #woocommerce-products-dashboard { @include wp-admin-reset("#woocommerce-products-dashboard"); @include reset; display: block !important; @@ -38,3 +39,5 @@ body.js.is-fullscreen-mode { } } } + +@import "products-app/sidebar-dataviews/style.scss"; diff --git a/packages/js/product-editor/typings/index.d.ts b/packages/js/product-editor/typings/index.d.ts index 92aeddf3d87..1fb7d394b5b 100644 --- a/packages/js/product-editor/typings/index.d.ts +++ b/packages/js/product-editor/typings/index.d.ts @@ -31,6 +31,7 @@ declare module '@wordpress/core-data' { isResolving: boolean; hasResolved: boolean; }; + const store: string; } declare module '@wordpress/keyboard-shortcuts' { function useShortcut( @@ -43,3 +44,24 @@ declare module '@wordpress/keyboard-shortcuts' { declare module '@wordpress/router' { const privateApis; } + +declare module '@wordpress/edit-site/build-module/components/sync-state-with-url/use-init-edited-entity-from-url' { + export default function useInitEditedEntityFromURL(): void; +} + +declare module '@wordpress/edit-site/build-module/components/sidebar-navigation-screen' { + const SidebarNavigationScreen: React.FunctionComponent< { + title: string; + isRoot: boolean; + content: JSX.Element; + } >; + export default SidebarNavigationScreen; +} + +declare module '@wordpress/edit-site/build-module/components/site-hub' { + const SiteHub: React.FunctionComponent< { + ref: React.Ref; + isTransparent: boolean; + } >; + export default SiteHub; +} diff --git a/plugins/woocommerce-admin/webpack.config.js b/plugins/woocommerce-admin/webpack.config.js index cadd1251831..469d48e3f3a 100644 --- a/plugins/woocommerce-admin/webpack.config.js +++ b/plugins/woocommerce-admin/webpack.config.js @@ -186,6 +186,8 @@ const webpackConfig = { extensions: [ '.json', '.js', '.jsx', '.ts', '.tsx' ], alias: { '~': path.resolve( __dirname + '/client' ), + 'react/jsx-dev-runtime': require.resolve( 'react/jsx-dev-runtime' ), + 'react/jsx-runtime': require.resolve( 'react/jsx-runtime' ), }, }, plugins: [ @@ -240,6 +242,10 @@ const webpackConfig = { return null; } + if ( request.startsWith( '@wordpress/dataviews' ) ) { + return null; + } + if ( request.startsWith( '@wordpress/edit-site' ) ) { // The external wp.editSite does not include edit-site components, so we need to skip requesting to external here. We can remove this once the edit-site components are exported in the external wp.editSite. // We use the edit-site components in the customize store. diff --git a/plugins/woocommerce/changelog/add-product_data_views_list b/plugins/woocommerce/changelog/add-product_data_views_list new file mode 100644 index 00000000000..7669d680be8 --- /dev/null +++ b/plugins/woocommerce/changelog/add-product_data_views_list @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Update webpack config to bundle in @wordpress/dataviews package. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db28d78d96a..ec49d327648 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -256,7 +256,7 @@ importers: version: 10.5.0(sass@1.69.5)(webpack@5.89.0(webpack-cli@3.3.12)) ts-jest: specifier: ~29.1.1 - version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -292,7 +292,7 @@ importers: version: 2.3.2 debug: specifier: ^4.3.4 - version: 4.3.4(supports-color@9.4.0) + version: 4.3.4(supports-color@8.1.1) dompurify: specifier: ^2.4.7 version: 2.4.7 @@ -453,7 +453,7 @@ importers: version: 27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)) ts-jest: specifier: ~29.1.1 - version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -2616,6 +2616,9 @@ importers: '@wordpress/data': specifier: wp-6.0 version: 6.6.1(react@17.0.2) + '@wordpress/dataviews': + specifier: ^4.2.0 + version: 4.2.0(@emotion/is-prop-valid@1.2.1)(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/date': specifier: wp-6.0 version: 4.6.1 @@ -2641,8 +2644,8 @@ importers: specifier: wp-6.0 version: 4.6.1 '@wordpress/icons': - specifier: wp-6.0 - version: 8.2.3 + specifier: 10.6.0 + version: 10.6.0(react@17.0.2) '@wordpress/interface': specifier: wp-6.0 version: 4.5.6(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react-with-direction@1.4.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2) @@ -2878,7 +2881,7 @@ importers: version: 5.0.5 ts-jest: specifier: ~29.1.1 - version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -2890,7 +2893,7 @@ importers: dependencies: debug: specifier: ^4.3.4 - version: 4.3.4(supports-color@9.4.0) + version: 4.3.4(supports-color@8.1.1) devDependencies: '@babel/core': specifier: ^7.23.5 @@ -2999,7 +3002,7 @@ importers: version: 1.2.5(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react-with-direction@1.4.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2) debug: specifier: ^4.3.4 - version: 4.3.4(supports-color@9.4.0) + version: 4.3.4(supports-color@8.1.1) prop-types: specifier: ^15.8.1 version: 15.8.1 @@ -3376,7 +3379,7 @@ importers: version: 3.34.0 debug: specifier: ^4.3.4 - version: 4.3.4(supports-color@9.4.0) + version: 4.3.4(supports-color@8.1.1) dompurify: specifier: ^2.4.7 version: 2.4.7 @@ -4666,7 +4669,7 @@ importers: version: 27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)) ts-jest: specifier: ~29.1.1 - version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3) @@ -4851,7 +4854,7 @@ importers: version: 1.2.2 ts-jest: specifier: ~29.1.1 - version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3) ts-loader: specifier: ^9.5.1 version: 9.5.1(typescript@5.3.3)(webpack@5.89.0(webpack-cli@3.3.12)) @@ -5105,23 +5108,23 @@ packages: '@ariakit/core@0.3.11': resolution: {integrity: sha512-+MnOeqnA4FLI/7vqsZLbZQHHN4ofd9kvkNjz44fNi0gqmD+ZbMWiDkFAvZII75dYnxYw5ZPpWjA4waK22VBWig==} - '@ariakit/core@0.3.8': - resolution: {integrity: sha512-LlSCwbyyozMX4ZEobpYGcv1LFqOdBTdTYPZw3lAVgLcFSNivsazi3NkKM9qNWNIu00MS+xTa0+RuIcuWAjlB2Q==} - '@ariakit/core@0.4.5': resolution: {integrity: sha512-e294+bEcyzt/H/kO4fS5/czLAlkF7PY+Kul3q2z54VY+GGay8NlVs9UezAB7L4jUBlYRAXwp7/1Sq3R7b+MZ7w==} + '@ariakit/core@0.4.9': + resolution: {integrity: sha512-nV0B/OTK/0iB+P9RC7fudznYZ8eR6rR1F912Zc54e3+wSW5RrRvNOiRxyMrgENidd4R7cCMDw77XJLSBLKgEPQ==} + '@ariakit/react-core@0.3.14': resolution: {integrity: sha512-16Qj6kDPglpdWtU5roY9q+G66naOjauTY5HvUIaL2aLY0187ATaRrABIKoMMzTtJyhvsud4jFlzivz+/zCQ8yw==} peerDependencies: react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - '@ariakit/react-core@0.3.9': - resolution: {integrity: sha512-K1Rcxr6FpF0n3L7Uvo+e5hm+zqoZmXLRcYF/skI+/j+ole+uNbnsnfGhG1avqJlklqH4bmkFkjZzmMdOnUC0Ig==} + '@ariakit/react-core@0.4.10': + resolution: {integrity: sha512-r6DZmtHBmSoOj848+RpBwdZy/55YxPhMhfH14JIO2OLn1F6iSFkQwR7AAGpIrlYycWJFSF7KrQu50O+SSfFJdQ==} peerDependencies: - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 '@ariakit/react-core@0.4.5': resolution: {integrity: sha512-ciTYPwpj/+mdA+EstveEnoygbx5e4PXQJxfkLKy4lkTkDJJUS9GcbYhdnIFJVUta6P1YFvzkIKo+/y9mcbMKJg==} @@ -5135,11 +5138,11 @@ packages: react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - '@ariakit/react@0.3.9': - resolution: {integrity: sha512-gC+gibh2go8wvBqzYXavlHKwAfmee5GUMrPSQ9WBBLIfm9nQElujxcHJydaRx+ULR5FbOnbZVC3vU2ic8hSrNw==} + '@ariakit/react@0.4.10': + resolution: {integrity: sha512-c1+6sNLj57aAXrBZMCVGG+OXeFrPAG0TV1jT7oPJcN/KLRs3aCuO3CCJVep/eKepFzzK01kNRGYX3wPT1TXPNw==} peerDependencies: - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 '@ariakit/react@0.4.5': resolution: {integrity: sha512-GUHxaOY1JZrJUHkuV20IY4NWcgknhqTQM0qCQcVZDCi+pJiWchUjTG+UyIr/Of02hU569qnQ7yovskCf+V3tNg==} @@ -6918,18 +6921,12 @@ packages: '@floating-ui/core@0.6.2': resolution: {integrity: sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg==} - '@floating-ui/core@0.7.3': - resolution: {integrity: sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==} - '@floating-ui/core@1.5.2': resolution: {integrity: sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==} '@floating-ui/dom@0.4.5': resolution: {integrity: sha512-b+prvQgJt8pieaKYMSJBXHxX/DYwdLsAWxKYqnO5dO2V4oo/TYBZJAUQCVNjTWWsrs6o4VDrNcP9+E70HAhJdw==} - '@floating-ui/dom@0.5.4': - resolution: {integrity: sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==} - '@floating-ui/dom@1.5.3': resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} @@ -6939,12 +6936,6 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react-dom@0.7.2': - resolution: {integrity: sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - '@floating-ui/react-dom@1.3.0': resolution: {integrity: sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==} peerDependencies: @@ -7800,12 +7791,6 @@ packages: '@radix-ui/primitive@1.0.1': resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} - '@radix-ui/react-arrow@1.0.2': - resolution: {integrity: sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-arrow@1.0.3': resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} peerDependencies: @@ -7819,12 +7804,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-collection@1.0.2': - resolution: {integrity: sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-collection@1.0.3': resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} peerDependencies: @@ -7872,11 +7851,6 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-direction@1.0.0': - resolution: {integrity: sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-direction@1.0.1': resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: @@ -7892,12 +7866,6 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-dismissable-layer@1.0.3': - resolution: {integrity: sha512-nXZOvFjOuHS1ovumntGV7NNoLaEp9JEvTht3MBjP44NSW5hUKj/8OnfN3+8WmB+CEhN44XaGhpHoSsUIEl5P7Q==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-dismissable-layer@1.0.4': resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} peerDependencies: @@ -7911,12 +7879,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-dropdown-menu@2.0.4': - resolution: {integrity: sha512-y6AT9+MydyXcByivdK1+QpjWoKaC7MLjkS/cH1Q3keEyMvDkiY85m8o2Bi6+Z1PPUlCsMULopxagQOSfN0wahg==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-focus-guards@1.0.0': resolution: {integrity: sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==} peerDependencies: @@ -7937,12 +7899,6 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-focus-scope@1.0.2': - resolution: {integrity: sha512-spwXlNTfeIprt+kaEWE/qYuYT3ZAqJiAGjN/JgdvgVDTu8yc+HuX+WOWXrKliKnLnwck0F6JDkqIERncnih+4A==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-focus-scope@1.0.3': resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} peerDependencies: @@ -7970,18 +7926,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-menu@2.0.4': - resolution: {integrity: sha512-mzKR47tZ1t193trEqlQoJvzY4u9vYfVH16ryBrVrCAGZzkgyWnMQYEZdUkM7y8ak9mrkKtJiqB47TlEnubeOFQ==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - - '@radix-ui/react-popper@1.1.1': - resolution: {integrity: sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-popper@1.1.2': resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} peerDependencies: @@ -8001,12 +7945,6 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-portal@1.0.2': - resolution: {integrity: sha512-swu32idoCW7KA2VEiUZGBSu9nB6qwGdV6k6HYhUoOo3M1FFpD+VgLzUqtt3mwL1ssz7r2x8MggpLSQach2Xy/Q==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-portal@1.0.3': resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} peerDependencies: @@ -8032,12 +7970,6 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-primitive@1.0.2': - resolution: {integrity: sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-primitive@1.0.3': resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -8051,12 +7983,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-roving-focus@1.0.3': - resolution: {integrity: sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-roving-focus@1.0.4': resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} peerDependencies: @@ -8101,11 +8027,6 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-slot@1.0.1': - resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-slot@1.0.2': resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: @@ -8187,11 +8108,6 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-use-escape-keydown@1.0.2': - resolution: {integrity: sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-use-escape-keydown@1.0.3': resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: @@ -8224,11 +8140,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-rect@1.0.0': - resolution: {integrity: sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-use-rect@1.0.1': resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} peerDependencies: @@ -8238,11 +8149,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-size@1.0.0': - resolution: {integrity: sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - '@radix-ui/react-use-size@1.0.1': resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} peerDependencies: @@ -8265,9 +8171,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/rect@1.0.0': - resolution: {integrity: sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==} - '@radix-ui/rect@1.0.1': resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} @@ -10432,11 +10335,19 @@ packages: '@use-gesture/core@10.3.0': resolution: {integrity: sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A==} + '@use-gesture/core@10.3.1': + resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==} + '@use-gesture/react@10.3.0': resolution: {integrity: sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA==} peerDependencies: react: '>= 16.8.0' + '@use-gesture/react@10.3.1': + resolution: {integrity: sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==} + peerDependencies: + react: '>= 16.8.0' + '@webassemblyjs/ast@1.11.1': resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} @@ -10693,6 +10604,10 @@ packages: resolution: {integrity: sha512-mOQtwpY5hUt4vMLyshZPPV1x9MBRF2FimUjIImfYJb1x8o6jY4npikzWplAfWYQUJJjWfw/1NmfqD7vUOh9+ww==} engines: {node: '>=12'} + '@wordpress/a11y@4.6.0': + resolution: {integrity: sha512-dSYGLgntqQCAiHBnNxttLOUZnH26m/BrIQdCXtb9JVJy5p68JAdFHbr6qFoOfOoTCvwUqE8cNS7K4GWfAJwT0w==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/api-fetch@3.23.1': resolution: {integrity: sha512-dmeigLuvqYAzpQ2hWUQT1P5VQAjkj9hS1z7PgNi1CcULFPbY8BWW+KiBETUu6Wm+rlSbUL2dC8qrA4JDv9ja5A==} @@ -10927,13 +10842,6 @@ packages: react: ^17.0.0 react-dom: ^17.0.0 - '@wordpress/components@25.13.0': - resolution: {integrity: sha512-Ym/5Xv7NnkJu40jCSmt/t6B8vT2ue2vobwDEz1FKlB0xGm5bzzh5589m2nZqqY459/Qm9dl5R4BKSdvKqKB2MQ==} - engines: {node: '>=12'} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - '@wordpress/components@25.16.0': resolution: {integrity: sha512-voQuMsO5JbH+JW33TnWurwwvpSb8IQ4XU5wyVMubX4TUwadt+/2ToNJbZIDXoaJPei7vbM81Ft+pH+zGlN8CyA==} engines: {node: '>=12'} @@ -10955,6 +10863,13 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 + '@wordpress/components@28.6.0': + resolution: {integrity: sha512-9YmA+7Tmz19oOfKifOF/VxcwJwyyLK8Y2LupK7ge6Oue0P1bMLs/9LBgZUBizoKMWmXYdzBm8pXf9Eyqq3PG0Q==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + '@wordpress/compose@3.25.3': resolution: {integrity: sha512-tCO2EnJCkCH548OqA0uU8V1k/1skz2QwBlHs8ZQSpimqUS4OWWsAlndCEFe4U4vDTqFt2ow7tzAir+05Cw8MAg==} @@ -10992,6 +10907,12 @@ packages: peerDependencies: react: ^18.0.0 + '@wordpress/compose@7.6.0': + resolution: {integrity: sha512-4ukiLfCOUkb0zmdFpPSVOnQkpNHTWqQUOCgpMykjKO0gRfa/rZ6dxcZUQ/KEYT5EKZkGCo9bR4lBhxjNVrgfug==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + peerDependencies: + react: ^18.0.0 + '@wordpress/core-commands@0.7.0': resolution: {integrity: sha512-kMfyANcDUmA2+4EfEZuDVNFOWKEOJe7oEaZtC6tFRR1wYAlPYOzaQJxbtQMBzqhvHlQMORaxDQNhaoJ8+ac8MQ==} engines: {node: '>=12'} @@ -11042,6 +10963,12 @@ packages: peerDependencies: react: ^17.0.0 + '@wordpress/data@10.6.0': + resolution: {integrity: sha512-u6g1IeK3Vv0Ulr/0jPWU5wpde+flWH1SDvqgc50GjG2v03NWqzie8zTGGeHo8Fque7s/UNbGYKlzrbM3+dPl5g==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + peerDependencies: + react: ^18.0.0 + '@wordpress/data@4.27.3': resolution: {integrity: sha512-5763NgNV9IIa1CC3Q80dAvrH6108tJtj3IrHfUCZmUk1atSNsOMBCkLdQ7tGTTi2JFejeGEMg1LJI22JD5zM6Q==} @@ -11081,14 +11008,16 @@ packages: peerDependencies: react: ^18.0.0 + '@wordpress/dataviews@4.2.0': + resolution: {integrity: sha512-rCnMbEVXKZYgQmJO7S448KPVh78DTHgfJ+B5H937l/HX8+Gd0OlkpbKi4C4UZUj0k/xwY7ccKERYurq3W8/NFg==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + peerDependencies: + react: ^18.0.0 + '@wordpress/date@4.44.0': resolution: {integrity: sha512-WrSAg+gbRN5YB/YZhQnJMNKj80efc+6taVYq3VjSzp27CPxh75qTE5N56TJWGKZbB8mqCIEWy6eOXhIoBW19mQ==} engines: {node: '>=12'} - '@wordpress/date@4.47.0': - resolution: {integrity: sha512-HIruX+wMaQWKYLCFIu6JeEEoqRYkhpL4cWfZ1lJG78wNsgq3vRiHzXQaXHcbmJQCq0PZOxtmeSzldPiUMFVNpg==} - engines: {node: '>=12'} - '@wordpress/date@4.57.0': resolution: {integrity: sha512-azUXRQDhxoCkME7c+0Cw/aCZmyoQeTXhWJYtZBFyPU5wsIXSv/Ucp3WggJR7OSKFnE5rSp5qpCt/nihfLLfZWQ==} engines: {node: '>=12'} @@ -11097,6 +11026,10 @@ packages: resolution: {integrity: sha512-7/w2pzCDvzbidqAl2Rhd/FeA6QZhZmb03Y7rPIO0eJR33L8QWnLiyw+r4Et2DLji8A7N8/gcc+hsRL6lcEsGMA==} engines: {node: '>=12'} + '@wordpress/date@5.6.0': + resolution: {integrity: sha512-uB/FaNHudbs4DgaPGld+Ckvoo8kYvxcDhVyJ6Io3MgONMcsDr4KR3lOc50MprbNZPbXG2KB0CTgHA+PHNxP9iQ==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/dependency-extraction-webpack-plugin@2.9.0': resolution: {integrity: sha512-Eo8ByPd3iZ6az4UmdLD2xYLp1/7os/H80l28Y5OlS4DozkD3vcWCBReynWoBax74u3oJ9wWN5b/8oSxGwIKXYQ==} peerDependencies: @@ -11133,6 +11066,10 @@ packages: resolution: {integrity: sha512-ilOkjXejcnJMxnq1gTVkBnDPP9W+XjlEe1TIfaMKcCwKsfsNy6bgURxWl1qIM2dPjH+5KK65bPjW0XELTMJy4w==} engines: {node: '>=12'} + '@wordpress/deprecated@4.6.0': + resolution: {integrity: sha512-XQbF7SIb43I4Ey7nEDqowm7YJgzoUpdmZfNBN01/UXKUZ0FNaKzf2LCNjOCwfEfRE7AroyUgMR40qWVBBs+GKQ==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/dom-ready@3.27.0': resolution: {integrity: sha512-X7yVAm/JL5UKNfttAN2Ak3suEyOag/MPfr/aX8L2k/od71a6zJBkpMcdKaVPVfIPj9HcrW6ROrfINySPtoGCLA==} engines: {node: '>=12'} @@ -11149,6 +11086,10 @@ packages: resolution: {integrity: sha512-G6OnfLLC0MIWi9efTW6DMNEtEoy7tCoV0MxD19gUuG3/rDOi8RgHYwuNCvt6ieQMISiLiHnsg4tZc4D45zdfZA==} engines: {node: '>=12'} + '@wordpress/dom-ready@4.6.0': + resolution: {integrity: sha512-3fX1O1abmp3++FpZMPnDQygeygUggqfEvWQQQ80di/ksMEo6DXvIdtXolwDQt9WIC1WetLdI7Mf3KKVJnruyxg==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/dom@2.18.0': resolution: {integrity: sha512-tM2WeQuSObl3nzWjUTF0/dyLnA7sdl/MXaSe32D64OF89bjSyJvjUipI7gjKzI3kJ7ddGhwcTggGvSB06MOoCQ==} @@ -11156,10 +11097,6 @@ packages: resolution: {integrity: sha512-ympP0cK4ErQSFCRyrhjg8wAK7Wb5NqTUyiw1kV+2TQ35PKNG+TCXjYkk19Wc0kxiYZPFtbxk8OPp40e8Up7y7g==} engines: {node: '>=12'} - '@wordpress/dom@3.47.0': - resolution: {integrity: sha512-SY6wfAc4yrXYil8fm/uyeKQnPjGuc0G9Q1/5pUKO6dssst8fClsrxy+hXNl0FYFGWnAZBqg5ccrwYydrFt5k/g==} - engines: {node: '>=12'} - '@wordpress/dom@3.57.0': resolution: {integrity: sha512-3vJ1Z5Lzb7kfMoB8ni275vFGIRrljWFQ2XsVfO6oA/HeoIfHAGVcR58GmbjyxwEgClrizMGIkbs9ubrRpontLQ==} engines: {node: '>=12'} @@ -11168,6 +11105,10 @@ packages: resolution: {integrity: sha512-wdWBzfxU8iUPpxxTACkFpYbEoC0f+Hqs24IYOkhn/8ERp2LFpUdFcwF7/DmY6agSpUs8iWT/2hSGdUz9Lw2f0w==} engines: {node: '>=12'} + '@wordpress/dom@4.6.0': + resolution: {integrity: sha512-ZCjMOya5dTkzgp/vTq7w1qpvVQDPoF7sJpalARUUQjeMUkUw/PTLYvvXJ3gARBCgaEdD85QjLorpxnJVz1XNng==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/e2e-test-utils-playwright@1.0.1': resolution: {integrity: sha512-DNR45Q0px6p3XLnJzRXANIXSQ1OKLdWCwQLQctuSmhVyqSyKS0VZApiYVoaPTKLEdxl+WeJ7jN153q1vUa5Lcg==} engines: {node: '>=18.12.0', npm: '>=8.19.2'} @@ -11273,6 +11214,10 @@ packages: resolution: {integrity: sha512-/d/lWBDYYgzE2yeXYvPnjMSDG1EdQs5TSLdjM/drQVJMxWayFqAPaF/pVczLHCPYfjgyJN4Zc+bneAKj6dEiLw==} engines: {node: '>=12'} + '@wordpress/element@6.6.0': + resolution: {integrity: sha512-IvSocvmd0fNus/XZo7K1EU4UD7aOKUdi3Y7pFUW2ljBbL3vuXk3E+6bwYahCjUIlBhpgGuCjemWTdg2Awzfmiw==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/env@10.5.0': resolution: {integrity: sha512-Hx+fi6qTEAuycznulkuMi4d5RDPZ6lPPAxaylpCwXNX2hgx5jrrpgnY4Zn0chBgZMpShO7BbA+zNDq2E6evvTw==} engines: {node: '>=18.12.0', npm: '>=8.19.2'} @@ -11289,6 +11234,10 @@ packages: resolution: {integrity: sha512-DkTDo1Qhvs9rfobBpg5vXAOKaev3Jox8R5ryvYIhql5chrkj/V5k2ZzwUChFXxYmivVkWacCwDGmDmwe2ex/ag==} engines: {node: '>=12'} + '@wordpress/escape-html@3.6.0': + resolution: {integrity: sha512-NY9As0uJ81TPTogBzD6G/m7L4+sjvkjTEKkNsHLD5aEYxRX+RHlPYPyyd6y4CmlOkttwymbV9eKNP+LrfX5zZQ==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/eslint-plugin@12.9.0': resolution: {integrity: sha512-R6dTvD4uFYeoUJFZNUhm1CSwthC0Pl0RIY057Y9oUvGSqjjm7RqRIwKrMlw3dO0P9KoBGGHUox8NUj6EciRXww==} engines: {node: '>=12', npm: '>=6.9'} @@ -11358,8 +11307,8 @@ packages: resolution: {integrity: sha512-4sIngmH64M1jzcprfkffo1GHsQbd/QNbTweq6cSPIJNorKfE63Inf59NQ6r0pq6+Nz+cuq64eMz5v4eyngjZ/A==} engines: {node: '>=12'} - '@wordpress/hooks@4.4.0': - resolution: {integrity: sha512-KO0gUx0KLhH3XCatg9ZOU1TH0fgyQUccAEIM8liErfgmrabHl8JhDoR2Uk5k0jNKZNPog7XxvKgPFVtCzvzQig==} + '@wordpress/hooks@4.6.0': + resolution: {integrity: sha512-FWJhubBXeyRhx12YUmxT9pNoV9Azvx8nkynhduV+RNgA+F2SXoOf15pr+USPV//m3Bx031GN/wPHjgUCbC6+XA==} engines: {node: '>=18.12.0', npm: '>=8.19.2'} '@wordpress/html-entities@3.24.0': @@ -11378,6 +11327,10 @@ packages: resolution: {integrity: sha512-Nb0nCYIdTEehWJ6HoA76bxpseKDY/12rYZ10eqf5OSr6oMvtyJ5j4fkNMKuHFQ00Mhppl9fkYWp2c8ZzBcp5Vw==} engines: {node: '>=12'} + '@wordpress/html-entities@4.6.0': + resolution: {integrity: sha512-ypTlGwDKw7jpmu9rneErkkq9dFHXzju8SGdEWkVAeqhRS9Ifri9DvmrovASB2c5IPY+Ijwh4YlVkx1yNBRHr5w==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/i18n@3.20.0': resolution: {integrity: sha512-SIoOJFB4UrrYAScS4H91CYCLW9dX3Ghv8pBKc/yHGculb1AdGr6gRMlmJxZV62Cn3CZ4Ga86c+FfR+GiBu0JPg==} hasBin: true @@ -11392,11 +11345,6 @@ packages: engines: {node: '>=12'} hasBin: true - '@wordpress/i18n@4.54.0': - resolution: {integrity: sha512-gSKBopBN9rY9GhNy3CXLK3n4D5viuBTObvcu3blu4SFqkHl+Ws1Gx0tHbpypfV80ESrOyMXHJIAqWgBD8d4Hew==} - engines: {node: '>=12'} - hasBin: true - '@wordpress/i18n@4.57.0': resolution: {integrity: sha512-VYWYHE+7NxnZvE9Swhhe4leQcn0jHNkzRAEV36TkfAL/MvrQYCRh71KLTvKhsilG96HUQdBwjH0VPLmYEmR3sg==} engines: {node: '>=12'} @@ -11412,6 +11360,15 @@ packages: engines: {node: '>=18.12.0', npm: '>=8.19.2'} hasBin: true + '@wordpress/i18n@5.6.0': + resolution: {integrity: sha512-xTpwuRh0owYFlgRHUbUAQIWr8ye3FC0ZsjDIOskJaNkrheAU9ZWKJDcmQmPvi01Udml4g9LUIaffkcRd2kyW2g==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + hasBin: true + + '@wordpress/icons@10.6.0': + resolution: {integrity: sha512-dy58bQFVee2izXA65Ptar1f8mVhL1hilOJI3BWbLWmxHr9H4VjI0ohjW4ZkAhahBG2yIvKZja/HaFMTs5O/7Xg==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/icons@4.1.0': resolution: {integrity: sha512-1FpEjT9kJbr0cWbgdgIwd2DoeerWijcVx3qCZ/WMFKNElBH9lfZLuWPI1hpX102HGWFcEi3VlbVpdBGeCeYQWg==} engines: {node: '>=12'} @@ -11432,10 +11389,6 @@ packages: resolution: {integrity: sha512-QkJRDNgSJzfU3OCVr5X9P3Au3MIag2yT4dzM3Ej6VfrF0SPfFgMwroXKSdNEHmCCG7AwtzGOjaqjpQ3y9vRMkA==} engines: {node: '>=12'} - '@wordpress/icons@9.38.0': - resolution: {integrity: sha512-K+rSZM1eKuWh+rXeMWNLj4dT0a3RJSzoUUh9UDQZCSdnThyAyZECGEKfHSCfd28/yabxLKaziXrb5/MVBrPjZw==} - engines: {node: '>=12'} - '@wordpress/icons@9.48.0': resolution: {integrity: sha512-47efXMuqX8Qbf7sFyYeUJ0TPjs3tNqnjHUn3WGc7Gq1IIYD6EGYFmCzPAfciUIXwRBhez2oC4y6IAXl5GP3KBw==} engines: {node: '>=12'} @@ -11473,6 +11426,10 @@ packages: resolution: {integrity: sha512-qUMqZMLlunwY2J31HG6NZwD2kBIqcwvIDBmdQYvVuQ2aDGeB2Z6sVPXyHCqGfh2ynFfaIL8bDtjW5UtYGPUI4A==} engines: {node: '>=12'} + '@wordpress/is-shallow-equal@5.6.0': + resolution: {integrity: sha512-WjxXleJePz9scpTXMTl//mn3AgEBqdHd56pWtaDgz9Ub7O5H8AMNa2BU4VDK8OOQ3iwpAUgqGhaTRK5GjbaeSA==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/jest-console@3.10.0': resolution: {integrity: sha512-iS1GSO+o7+p2PhvScOquD+IK7WqmVxa2s9uTUQyNEo06f9EUv6KNw0B1iZ00DpbgLqDCiczfdCNapC816UXIIA==} engines: {node: '>=8'} @@ -11572,6 +11529,10 @@ packages: resolution: {integrity: sha512-GLKho4gAFbqgmP3GxEPP5iSS2WwOtqX0xL0zVjElNC/uHKCULyZ2UlyDAc2clN5wiVNf3hC4A1BsxzKeKIMNFQ==} engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/keycodes@4.6.0': + resolution: {integrity: sha512-7jmKM1BLyoQPLXFl+3FPaKBrLEe7kUIkBMGS88083SQtXXFcW8sYQt5jd6E1yY6EAnniGveUNrv0C9Lbaipx3w==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/lazy-import@1.34.0': resolution: {integrity: sha512-ZF4YhWDJtvlev1GqZ7FRr2CPg5Vssw6lb4gn2OH56/KWuHf/LrBPVdshXR6ujDPvgUMnNFRf39ofHIENoj7JPA==} engines: {npm: '>=6.9.0'} @@ -11723,6 +11684,12 @@ packages: resolution: {integrity: sha512-4vMhlu40+qxkt6lyCv2KWCx9bP7hcpPC9GXj9Kq3gwKIzSSHoqbYs3V8HYeGWrG9g7JWMFN9Pkdy8Bm61ZsKuQ==} engines: {node: '>=12'} + '@wordpress/primitives@4.6.0': + resolution: {integrity: sha512-uu4ANmgwslB2YOyIBQDSwKTQXXqGDL9Gz5INe+UeJZBMt2uU/TGEjKcZ63dqbuM8mqlPAcdVGL52RCt7mIKEhQ==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + peerDependencies: + react: ^18.0.0 + '@wordpress/priority-queue@1.11.2': resolution: {integrity: sha512-ulwmUOklY3orn1xXpcPnTyGWV5B/oycxI+cHZ6EevBVgM5sq+BW3xo0PKLR/MMm6UNBtFTu/71QAJrNZcD6V1g==} @@ -11734,6 +11701,10 @@ packages: resolution: {integrity: sha512-g4Oka9aQFVPQUhXkKhHT6BoyTEdCG6S0TUvP4SP16PbkhbvIFwZ25GRQb2ERCVTdseCuDIM5YP0kwZd3NqTlGg==} engines: {node: '>=12'} + '@wordpress/priority-queue@3.6.0': + resolution: {integrity: sha512-r2cyisWaqDLesIqC8BqWoXyNIxt1lwjvevw5Kijl9zxzxfYBsNQlu7RI1JNYgnjbDQQirWukFgprt7tdzhwssQ==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/private-apis@0.20.0': resolution: {integrity: sha512-byyPRUNAD8/ca9N8gP2rUr8DHuMbzSoXO03nP8g3cecTN6iCOWqFDm6adkrbiAX527N9Ip+GOrRJd7Tta4kRIg==} engines: {node: '>=12'} @@ -11777,6 +11748,12 @@ packages: peerDependencies: redux: '>=4' + '@wordpress/redux-routine@5.6.0': + resolution: {integrity: sha512-CQkO+JZefPJLNBh5iBup2DRCXfUoPfEZeo2mhO91tSbBmrP08v1Pdk6YLsa8gNDXp4qJbFhNHMGCqRzEioMOhA==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + peerDependencies: + redux: '>=4' + '@wordpress/reusable-blocks@3.20.0': resolution: {integrity: sha512-2Wp1W704eYfTdCrYx+EKr5VbW/Z0AX24M8+FxWmhFlGjWpdzGl9shuMKv6cLfXeLDitU8fyHILXAVAXsvRvK3A==} engines: {node: '>=12'} @@ -11807,15 +11784,15 @@ packages: peerDependencies: react: ^17.0.0 - '@wordpress/rich-text@6.24.0': - resolution: {integrity: sha512-RkvzK8zvLgpd7i5dlL6zs+Dig1lZNSZf/3sYyjX6RalISXNuxF6Zn8Or7kBcq7EcYmey0LMlVIl5FTZ2l7HSIA==} + '@wordpress/rich-text@6.34.0': + resolution: {integrity: sha512-qeHPgSaI6UolAA9s8ShlbqjWtlh1kTIOMKATDZD6GOACZurXh9ZVJxxsE95FSmLEu4SDmYJ0b2sZlh92yJuaPw==} engines: {node: '>=12'} peerDependencies: react: ^18.0.0 - '@wordpress/rich-text@6.34.0': - resolution: {integrity: sha512-qeHPgSaI6UolAA9s8ShlbqjWtlh1kTIOMKATDZD6GOACZurXh9ZVJxxsE95FSmLEu4SDmYJ0b2sZlh92yJuaPw==} - engines: {node: '>=12'} + '@wordpress/rich-text@7.6.0': + resolution: {integrity: sha512-XxlfrlwfCPX7f3u9DMinouYNM9PDBMeGZb4MlK2Fbrc8ympaTZOdH4U74VR3jgv0Eusx6vxFEA5JVVXpW/xS2w==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} peerDependencies: react: ^18.0.0 @@ -11926,6 +11903,10 @@ packages: resolution: {integrity: sha512-WhMKX/ETGUJr2GkaPgGwFF8gTU/PgikfvE2b2ZDjUglxIPYnujBa9S6w+kQPzwGniGJutHL1DFK+TmAaxoci9A==} engines: {node: '>=12'} + '@wordpress/undo-manager@1.6.0': + resolution: {integrity: sha512-Sl2rG/7t5zTQOgp+jOPn5m27sKd1DJIX/EGhM6LtRcjXZqa0rLDJXal1xWfkZk5oghaqW1TAwXJsg9UdAlh7Nw==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/url@2.22.2': resolution: {integrity: sha512-aqpYKQXzyzkCOm+GzZRYlLb+wh58g0cwR1PaKAl0UXaBS4mdS+X6biMriylb4P8CVC/RR7CSw5XI20JC24KDwQ==} @@ -11978,6 +11959,10 @@ packages: resolution: {integrity: sha512-Xs37x0IkvNewPNKs1A8cnw5xLb+AqwUqqCsH4+5Sjat5GDqP86mHgLfRIlE4d6fBYg+q6tO7DVPG49TT3/wzgA==} engines: {node: '>=12'} + '@wordpress/warning@3.6.0': + resolution: {integrity: sha512-pm57z1LZkzfQsXsji6yxcP0XSymKbvP087vJLlMkmLf+MoNVyTD6UvFpXl8hRSH6C6pySoJSgGFXaH81CRuO2Q==} + engines: {node: '>=18.12.0', npm: '>=8.19.2'} + '@wordpress/widgets@3.24.0': resolution: {integrity: sha512-bgjUoBjHKhyM2u7QrTScll7hCFDrHw0OxZWGbPXOGfE0VUgaej/d8QV5re7I+sOIi0g8+XLYQE0fwEyANt1iUg==} peerDependencies: @@ -16078,6 +16063,20 @@ packages: react-dom: optional: true + framer-motion@11.3.30: + resolution: {integrity: sha512-9VmqGe9OIjfMoCcs+ZsKXlv6JaG5QagKX2F1uSbkG3Z33wgjnz60Kw+CngC1M49rDYau+Y9aL+8jGagAwrbVyw==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + framer-motion@6.5.1: resolution: {integrity: sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==} peerDependencies: @@ -25466,10 +25465,10 @@ snapshots: '@ariakit/core@0.3.11': {} - '@ariakit/core@0.3.8': {} - '@ariakit/core@0.4.5': {} + '@ariakit/core@0.4.9': {} + '@ariakit/react-core@0.3.14(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@ariakit/core': 0.3.11 @@ -25486,9 +25485,9 @@ snapshots: react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.2.0(react@18.3.1) - '@ariakit/react-core@0.3.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': + '@ariakit/react-core@0.4.10(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@ariakit/core': 0.3.8 + '@ariakit/core': 0.4.9 '@floating-ui/dom': 1.5.3 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -25514,9 +25513,9 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@ariakit/react@0.3.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': + '@ariakit/react@0.4.10(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@ariakit/react-core': 0.3.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@ariakit/react-core': 0.4.10(react-dom@17.0.2(react@17.0.2))(react@17.0.2) react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -25703,7 +25702,7 @@ snapshots: '@wordpress/primitives': 3.55.0 '@wordpress/react-i18n': 3.55.0 classnames: 2.3.2 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) react: 17.0.2 react-dom: 17.0.2(react@17.0.2) react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) @@ -25807,7 +25806,7 @@ snapshots: '@babel/traverse': 7.23.5 '@babel/types': 7.23.5 convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 lodash: 4.17.21 @@ -25830,7 +25829,7 @@ snapshots: '@babel/traverse': 7.23.5 '@babel/types': 7.23.5 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -25850,7 +25849,7 @@ snapshots: '@babel/traverse': 7.23.5 '@babel/types': 7.23.5 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -29949,7 +29948,7 @@ snapshots: '@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@17.0.71)(react@17.0.2))(@types/react@17.0.71)(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@emotion/babel-plugin': 11.11.0 '@emotion/is-prop-valid': 1.2.1 '@emotion/react': 11.11.1(@types/react@17.0.71)(react@17.0.2) @@ -29964,7 +29963,7 @@ snapshots: '@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@17.0.71)(react@18.3.1))(@types/react@17.0.71)(react@18.3.1)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@emotion/babel-plugin': 11.11.0 '@emotion/is-prop-valid': 1.2.1 '@emotion/react': 11.11.1(@types/react@17.0.71)(react@18.3.1) @@ -30132,8 +30131,6 @@ snapshots: '@floating-ui/core@0.6.2': {} - '@floating-ui/core@0.7.3': {} - '@floating-ui/core@1.5.2': dependencies: '@floating-ui/utils': 0.1.6 @@ -30142,10 +30139,6 @@ snapshots: dependencies: '@floating-ui/core': 0.6.2 - '@floating-ui/dom@0.5.4': - dependencies: - '@floating-ui/core': 0.7.3 - '@floating-ui/dom@1.5.3': dependencies: '@floating-ui/core': 1.5.2 @@ -30169,27 +30162,12 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@floating-ui/react-dom@0.7.2(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@floating-ui/dom': 0.5.4 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - use-isomorphic-layout-effect: 1.1.2(@types/react@17.0.71)(react@17.0.2) - transitivePeerDependencies: - - '@types/react' - '@floating-ui/react-dom@1.3.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@floating-ui/dom': 1.5.3 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - '@floating-ui/react-dom@2.0.4(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@floating-ui/dom': 1.5.3 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@floating-ui/react-dom@2.0.4(react-dom@18.3.1(react@17.0.2))(react@17.0.2)': dependencies: '@floating-ui/dom': 1.5.3 @@ -31560,7 +31538,7 @@ snapshots: '@oclif/color': 1.0.13 '@oclif/core': 2.15.0(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3) chalk: 4.1.2 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) fs-extra: 9.1.0 http-call: 5.3.0 load-json-file: 5.3.0 @@ -32030,7 +32008,7 @@ snapshots: '@puppeteer/browsers@1.4.6(typescript@5.3.2)': dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.3.0 @@ -32044,7 +32022,7 @@ snapshots: '@puppeteer/browsers@1.4.6(typescript@5.3.3)': dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.3.0 @@ -32058,7 +32036,7 @@ snapshots: '@puppeteer/browsers@1.9.0': dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.3.1 @@ -32080,13 +32058,6 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 - '@radix-ui/react-arrow@1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32107,16 +32078,6 @@ snapshots: '@types/react': 17.0.71 '@types/react-dom': 18.3.0 - '@radix-ui/react-collection@1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - '@radix-ui/react-context': 1.0.0(react@17.0.2) - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-slot': 1.0.1(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@radix-ui/react-collection@1.0.3(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32235,11 +32196,6 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@radix-ui/react-direction@1.0.0(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - react: 17.0.2 - '@radix-ui/react-direction@1.0.1(@types/react@17.0.71)(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -32276,17 +32232,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-dismissable-layer@1.0.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/primitive': 1.0.0 - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-use-callback-ref': 1.0.0(react@17.0.2) - '@radix-ui/react-use-escape-keydown': 1.0.2(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32315,21 +32260,6 @@ snapshots: '@types/react': 17.0.71 '@types/react-dom': 18.3.0 - '@radix-ui/react-dropdown-menu@2.0.4(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/primitive': 1.0.0 - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - '@radix-ui/react-context': 1.0.0(react@17.0.2) - '@radix-ui/react-id': 1.0.0(react@17.0.2) - '@radix-ui/react-menu': 2.0.4(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-use-controllable-state': 1.0.0(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - transitivePeerDependencies: - - '@types/react' - '@radix-ui/react-focus-guards@1.0.0(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -32372,15 +32302,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-focus-scope@1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-use-callback-ref': 1.0.0(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32433,50 +32354,6 @@ snapshots: optionalDependencies: '@types/react': 17.0.71 - '@radix-ui/react-menu@2.0.4(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/primitive': 1.0.0 - '@radix-ui/react-collection': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - '@radix-ui/react-context': 1.0.0(react@17.0.2) - '@radix-ui/react-direction': 1.0.0(react@17.0.2) - '@radix-ui/react-dismissable-layer': 1.0.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-focus-guards': 1.0.0(react@17.0.2) - '@radix-ui/react-focus-scope': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-id': 1.0.0(react@17.0.2) - '@radix-ui/react-popper': 1.1.1(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-portal': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-presence': 1.0.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-roving-focus': 1.0.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-slot': 1.0.1(react@17.0.2) - '@radix-ui/react-use-callback-ref': 1.0.0(react@17.0.2) - aria-hidden: 1.2.3 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-remove-scroll: 2.5.5(@types/react@17.0.71)(react@17.0.2) - transitivePeerDependencies: - - '@types/react' - - '@radix-ui/react-popper@1.1.1(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@floating-ui/react-dom': 0.7.2(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-arrow': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - '@radix-ui/react-context': 1.0.0(react@17.0.2) - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-use-callback-ref': 1.0.0(react@17.0.2) - '@radix-ui/react-use-layout-effect': 1.0.0(react@17.0.2) - '@radix-ui/react-use-rect': 1.0.0(react@17.0.2) - '@radix-ui/react-use-size': 1.0.0(react@17.0.2) - '@radix-ui/rect': 1.0.0 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - transitivePeerDependencies: - - '@types/react' - '@radix-ui/react-popper@1.1.2(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32529,13 +32406,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-portal@1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@radix-ui/react-portal@1.0.3(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32586,13 +32456,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@radix-ui/react-primitive@1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-slot': 1.0.1(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32613,21 +32476,6 @@ snapshots: '@types/react': 17.0.71 '@types/react-dom': 18.3.0 - '@radix-ui/react-roving-focus@1.0.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/primitive': 1.0.0 - '@radix-ui/react-collection': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - '@radix-ui/react-context': 1.0.0(react@17.0.2) - '@radix-ui/react-direction': 1.0.0(react@17.0.2) - '@radix-ui/react-id': 1.0.0(react@17.0.2) - '@radix-ui/react-primitive': 1.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-use-callback-ref': 1.0.0(react@17.0.2) - '@radix-ui/react-use-controllable-state': 1.0.0(react@17.0.2) - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - '@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.0.10)(@types/react@17.0.71)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 @@ -32756,12 +32604,6 @@ snapshots: '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) react: 18.3.1 - '@radix-ui/react-slot@1.0.1(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-compose-refs': 1.0.0(react@17.0.2) - react: 17.0.2 - '@radix-ui/react-slot@1.0.2(@types/react@17.0.71)(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -32930,12 +32772,6 @@ snapshots: '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) react: 18.3.1 - '@radix-ui/react-use-escape-keydown@1.0.2(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-use-callback-ref': 1.0.0(react@17.0.2) - react: 17.0.2 - '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@17.0.71)(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -32990,12 +32826,6 @@ snapshots: optionalDependencies: '@types/react': 17.0.71 - '@radix-ui/react-use-rect@1.0.0(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/rect': 1.0.0 - react: 17.0.2 - '@radix-ui/react-use-rect@1.0.1(@types/react@17.0.71)(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -33012,12 +32842,6 @@ snapshots: optionalDependencies: '@types/react': 17.0.71 - '@radix-ui/react-use-size@1.0.0(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/react-use-layout-effect': 1.0.0(react@17.0.2) - react: 17.0.2 - '@radix-ui/react-use-size@1.0.1(@types/react@17.0.71)(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -33054,10 +32878,6 @@ snapshots: '@types/react': 17.0.71 '@types/react-dom': 18.3.0 - '@radix-ui/rect@1.0.0': - dependencies: - '@babel/runtime': 7.25.0 - '@radix-ui/rect@1.0.1': dependencies: '@babel/runtime': 7.25.0 @@ -34593,7 +34413,7 @@ snapshots: style-loader: 1.3.0(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) terser-webpack-plugin: 4.2.3(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) ts-dedent: 2.2.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))))(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.89.0(webpack-cli@3.3.12)))(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) util-deprecate: 1.0.2 webpack: 4.47.0(webpack-cli@3.3.12(webpack@5.89.0)) webpack-dev-middleware: 3.7.3(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) @@ -34654,7 +34474,7 @@ snapshots: style-loader: 1.3.0(webpack@4.47.0) terser-webpack-plugin: 4.2.3(webpack@4.47.0) ts-dedent: 2.2.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.89.0))(webpack@4.47.0) + url-loader: 4.1.1(file-loader@6.2.0(webpack@4.47.0))(webpack@4.47.0) util-deprecate: 1.0.2 webpack: 4.47.0 webpack-dev-middleware: 3.7.3(webpack@4.47.0) @@ -35828,7 +35648,7 @@ snapshots: telejson: 6.0.8 terser-webpack-plugin: 4.2.3(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) ts-dedent: 2.2.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))))(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.89.0(webpack-cli@3.3.12)))(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) util-deprecate: 1.0.2 webpack: 4.47.0(webpack-cli@3.3.12(webpack@5.89.0)) webpack-dev-middleware: 3.7.3(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) @@ -35878,7 +35698,7 @@ snapshots: telejson: 6.0.8 terser-webpack-plugin: 4.2.3(webpack@4.47.0) ts-dedent: 2.2.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.89.0))(webpack@4.47.0) + url-loader: 4.1.1(file-loader@6.2.0(webpack@4.47.0))(webpack@4.47.0) util-deprecate: 1.0.2 webpack: 4.47.0 webpack-dev-middleware: 3.7.3(webpack@4.47.0) @@ -37549,7 +37369,6 @@ snapshots: '@types/react-dom@18.3.0': dependencies: '@types/react': 17.0.71 - optional: true '@types/react-outside-click-handler@1.3.3': dependencies: @@ -38009,7 +37828,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.56.0 '@typescript-eslint/type-utils': 5.56.0(eslint@8.55.0)(typescript@5.3.2) '@typescript-eslint/utils': 5.56.0(eslint@8.55.0)(typescript@5.3.2) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.55.0 grapheme-splitter: 1.0.4 ignore: 5.3.0 @@ -38028,7 +37847,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.55.0)(typescript@5.3.2) '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.2) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.55.0 graphemer: 1.4.0 ignore: 5.3.0 @@ -38047,7 +37866,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/utils': 5.62.0(eslint@8.55.0)(typescript@5.3.3) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.55.0 graphemer: 1.4.0 ignore: 5.3.0 @@ -38127,7 +37946,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.56.0 '@typescript-eslint/types': 5.56.0 '@typescript-eslint/typescript-estree': 5.56.0(typescript@5.3.2) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.55.0 optionalDependencies: typescript: 5.3.2 @@ -38139,7 +37958,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.2) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.55.0 optionalDependencies: typescript: 5.3.2 @@ -38151,7 +37970,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.55.0 optionalDependencies: typescript: 5.3.3 @@ -38349,6 +38168,8 @@ snapshots: '@use-gesture/core@10.3.0': {} + '@use-gesture/core@10.3.1': {} + '@use-gesture/react@10.3.0(react@17.0.2)': dependencies: '@use-gesture/core': 10.3.0 @@ -38359,6 +38180,16 @@ snapshots: '@use-gesture/core': 10.3.0 react: 18.3.1 + '@use-gesture/react@10.3.1(react@17.0.2)': + dependencies: + '@use-gesture/core': 10.3.1 + react: 17.0.2 + + '@use-gesture/react@10.3.1(react@18.3.1)': + dependencies: + '@use-gesture/core': 10.3.1 + react: 18.3.1 + '@webassemblyjs/ast@1.11.1': dependencies: '@webassemblyjs/helper-numbers': 1.11.1 @@ -38828,7 +38659,7 @@ snapshots: '@wordpress/a11y@3.47.0': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/dom-ready': 3.47.0 '@wordpress/i18n': 4.47.0 @@ -38844,6 +38675,12 @@ snapshots: '@wordpress/dom-ready': 3.27.0 '@wordpress/i18n': 4.6.1 + '@wordpress/a11y@4.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/dom-ready': 4.6.0 + '@wordpress/i18n': 5.6.0 + '@wordpress/api-fetch@3.23.1(react-native@0.73.0(@babel/core@7.23.5)(@babel/preset-env@7.23.6(@babel/core@7.23.5))(encoding@0.1.13)(react@17.0.2))': dependencies: '@babel/runtime': 7.25.0 @@ -38881,7 +38718,7 @@ snapshots: '@wordpress/api-fetch@6.44.0': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/i18n': 4.57.0 '@wordpress/url': 3.48.0 '@wordpress/api-fetch@7.0.1': @@ -38896,7 +38733,7 @@ snapshots: '@wordpress/autop@3.47.0': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/babel-plugin-import-jsx-pragma@1.1.3(@babel/core@7.12.9)': dependencies: @@ -38993,7 +38830,7 @@ snapshots: '@babel/plugin-transform-runtime': 7.23.4(@babel/core@7.24.7) '@babel/preset-env': 7.23.5(@babel/core@7.24.7) '@babel/preset-typescript': 7.23.3(@babel/core@7.24.7) - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/babel-plugin-import-jsx-pragma': 4.30.0(@babel/core@7.24.7) '@wordpress/browserslist-config': 5.30.0 '@wordpress/warning': 2.47.0 @@ -39015,7 +38852,7 @@ snapshots: '@wordpress/blob@3.47.0': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/blob@3.6.1': dependencies: @@ -39075,34 +38912,34 @@ snapshots: '@emotion/react': 11.11.1(@types/react@17.0.71)(react@17.0.2) '@emotion/styled': 11.11.0(@emotion/react@11.11.1(@types/react@17.0.71)(react@17.0.2))(@types/react@17.0.71)(react@17.0.2) '@react-spring/web': 9.7.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/a11y': 3.47.0 + '@wordpress/a11y': 3.57.0 '@wordpress/api-fetch': 6.44.0 '@wordpress/blob': 3.47.0 '@wordpress/blocks': 12.24.0(react@17.0.2) '@wordpress/commands': 0.18.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/compose': 6.24.0(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) - '@wordpress/date': 4.47.0 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/compose': 6.34.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) + '@wordpress/date': 4.57.0 + '@wordpress/deprecated': 3.57.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.34.0 - '@wordpress/escape-html': 2.47.0 + '@wordpress/escape-html': 2.57.0 '@wordpress/hooks': 3.57.0 - '@wordpress/html-entities': 3.47.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/html-entities': 3.57.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.48.0 - '@wordpress/is-shallow-equal': 4.47.0 + '@wordpress/is-shallow-equal': 4.57.0 '@wordpress/keyboard-shortcuts': 4.24.0(react@17.0.2) '@wordpress/keycodes': 3.57.0 '@wordpress/notices': 4.15.0(react@17.0.2) '@wordpress/preferences': 3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/private-apis': 0.29.0 - '@wordpress/rich-text': 6.24.0(react@17.0.2) + '@wordpress/rich-text': 6.34.0(react@17.0.2) '@wordpress/style-engine': 1.30.0 '@wordpress/token-list': 2.47.0 '@wordpress/url': 3.48.0 - '@wordpress/warning': 2.47.0 + '@wordpress/warning': 2.57.0 '@wordpress/wordcount': 3.47.0 change-case: 4.1.2 classnames: 2.3.2 @@ -39136,34 +38973,34 @@ snapshots: '@emotion/react': 11.11.1(@types/react@17.0.71)(react@18.3.1) '@emotion/styled': 11.11.0(@emotion/react@11.11.1(@types/react@17.0.71)(react@18.3.1))(@types/react@17.0.71)(react@18.3.1) '@react-spring/web': 9.7.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@wordpress/a11y': 3.47.0 + '@wordpress/a11y': 3.57.0 '@wordpress/api-fetch': 6.44.0 '@wordpress/blob': 3.47.0 '@wordpress/blocks': 12.24.0(react@18.3.1) '@wordpress/commands': 0.18.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@wordpress/compose': 6.24.0(react@18.3.1) - '@wordpress/data': 9.17.0(react@18.3.1) - '@wordpress/date': 4.47.0 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/compose': 6.34.0(react@18.3.1) + '@wordpress/data': 9.27.0(react@18.3.1) + '@wordpress/date': 4.57.0 + '@wordpress/deprecated': 3.57.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.34.0 - '@wordpress/escape-html': 2.47.0 + '@wordpress/escape-html': 2.57.0 '@wordpress/hooks': 3.57.0 - '@wordpress/html-entities': 3.47.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/html-entities': 3.57.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.48.0 - '@wordpress/is-shallow-equal': 4.47.0 + '@wordpress/is-shallow-equal': 4.57.0 '@wordpress/keyboard-shortcuts': 4.24.0(react@18.3.1) '@wordpress/keycodes': 3.57.0 '@wordpress/notices': 4.15.0(react@18.3.1) '@wordpress/preferences': 3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/private-apis': 0.29.0 - '@wordpress/rich-text': 6.24.0(react@18.3.1) + '@wordpress/rich-text': 6.34.0(react@18.3.1) '@wordpress/style-engine': 1.30.0 '@wordpress/token-list': 2.47.0 '@wordpress/url': 3.48.0 - '@wordpress/warning': 2.47.0 + '@wordpress/warning': 2.57.0 '@wordpress/wordcount': 3.47.0 change-case: 4.1.2 classnames: 2.3.2 @@ -39203,7 +39040,7 @@ snapshots: '@wordpress/compose': 5.5.0(react@18.3.1) '@wordpress/data': 6.15.0(react@18.3.1) '@wordpress/deprecated': 3.41.0 - '@wordpress/dom': 3.27.0 + '@wordpress/dom': 3.6.1 '@wordpress/element': 4.20.0 '@wordpress/hooks': 3.6.1 '@wordpress/html-entities': 3.24.0 @@ -39239,7 +39076,7 @@ snapshots: '@wordpress/block-editor@8.6.0(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react-with-direction@1.4.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@react-spring/web': 9.7.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/a11y': 3.47.0 '@wordpress/api-fetch': 6.21.0 @@ -39379,32 +39216,32 @@ snapshots: '@wordpress/block-library@8.24.1(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@preact/signals-core@1.5.1)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 + '@wordpress/a11y': 3.57.0 '@wordpress/api-fetch': 6.44.0 '@wordpress/autop': 3.47.0 '@wordpress/blob': 3.47.0 '@wordpress/block-editor': 12.15.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/blocks': 12.24.0(react@17.0.2) '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/compose': 6.24.0(react@17.0.2) + '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/core-data': 6.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) - '@wordpress/date': 4.47.0 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/data': 9.27.0(react@17.0.2) + '@wordpress/date': 4.57.0 + '@wordpress/deprecated': 3.57.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.34.0 - '@wordpress/escape-html': 2.47.0 + '@wordpress/escape-html': 2.57.0 '@wordpress/hooks': 3.57.0 - '@wordpress/html-entities': 3.47.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/html-entities': 3.57.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.48.0 '@wordpress/interactivity': 3.0.1(@preact/signals-core@1.5.1) '@wordpress/keycodes': 3.57.0 '@wordpress/notices': 4.15.0(react@17.0.2) - '@wordpress/primitives': 3.45.0 + '@wordpress/primitives': 3.55.0 '@wordpress/private-apis': 0.29.0 '@wordpress/reusable-blocks': 4.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/rich-text': 6.24.0(react@17.0.2) + '@wordpress/rich-text': 6.34.0(react@17.0.2) '@wordpress/server-side-render': 4.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/url': 3.48.0 '@wordpress/viewport': 5.24.0(react@17.0.2) @@ -39435,7 +39272,7 @@ snapshots: '@wordpress/block-serialization-default-parser@4.47.0': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/blocks@11.1.5(react@18.3.1)': dependencies: @@ -39446,7 +39283,7 @@ snapshots: '@wordpress/compose': 5.5.0(react@18.3.1) '@wordpress/data': 6.15.0(react@18.3.1) '@wordpress/deprecated': 3.41.0 - '@wordpress/dom': 3.27.0 + '@wordpress/dom': 3.6.1 '@wordpress/element': 4.20.0 '@wordpress/hooks': 3.6.1 '@wordpress/html-entities': 3.24.0 @@ -39530,7 +39367,7 @@ snapshots: '@wordpress/compose': 6.24.0(react@17.0.2) '@wordpress/data': 9.17.0(react@17.0.2) '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.24.0 '@wordpress/hooks': 3.57.0 '@wordpress/html-entities': 3.47.0 @@ -39560,7 +39397,7 @@ snapshots: '@wordpress/compose': 6.24.0(react@18.3.1) '@wordpress/data': 9.17.0(react@18.3.1) '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.24.0 '@wordpress/hooks': 3.57.0 '@wordpress/html-entities': 3.47.0 @@ -39641,9 +39478,9 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.22.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.36.0 '@wordpress/keyboard-shortcuts': 4.24.0(react@17.0.2) '@wordpress/private-apis': 0.20.0 @@ -39672,7 +39509,7 @@ snapshots: '@wordpress/compose': 4.2.0(react@18.3.1) '@wordpress/date': 4.44.0 '@wordpress/deprecated': 3.41.0 - '@wordpress/dom': 3.27.0 + '@wordpress/dom': 3.6.1 '@wordpress/element': 3.2.0 '@wordpress/hooks': 3.6.1 '@wordpress/i18n': 4.47.0 @@ -39820,7 +39657,7 @@ snapshots: '@wordpress/compose': 5.4.1(react@17.0.2) '@wordpress/date': 4.44.0 '@wordpress/deprecated': 3.41.0 - '@wordpress/dom': 3.27.0 + '@wordpress/dom': 3.6.1 '@wordpress/element': 4.4.1 '@wordpress/escape-html': 2.47.0 '@wordpress/hooks': 3.6.1 @@ -39868,7 +39705,7 @@ snapshots: '@wordpress/compose': 5.4.1(react@17.0.2) '@wordpress/date': 4.44.0 '@wordpress/deprecated': 3.41.0 - '@wordpress/dom': 3.27.0 + '@wordpress/dom': 3.6.1 '@wordpress/element': 4.4.1 '@wordpress/escape-html': 2.47.0 '@wordpress/hooks': 3.6.1 @@ -39904,7 +39741,7 @@ snapshots: '@wordpress/components@20.0.0(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@emotion/cache': 11.11.0 '@emotion/css': 11.11.2 '@emotion/react': 11.11.1(@types/react@17.0.71)(react@17.0.2) @@ -39925,7 +39762,7 @@ snapshots: '@wordpress/icons': 9.36.0 '@wordpress/is-shallow-equal': 4.24.0 '@wordpress/keycodes': 3.47.0 - '@wordpress/primitives': 3.45.0 + '@wordpress/primitives': 3.55.0 '@wordpress/rich-text': 5.20.0(react@17.0.2) '@wordpress/warning': 2.47.0 change-case: 4.1.2 @@ -39974,7 +39811,7 @@ snapshots: '@wordpress/icons': 9.36.0 '@wordpress/is-shallow-equal': 4.24.0 '@wordpress/keycodes': 3.47.0 - '@wordpress/primitives': 3.45.0 + '@wordpress/primitives': 3.55.0 '@wordpress/rich-text': 5.20.0(react@17.0.2) '@wordpress/warning': 2.47.0 change-case: 4.1.2 @@ -40001,70 +39838,6 @@ snapshots: - '@types/react' - supports-color - '@wordpress/components@25.13.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': - dependencies: - '@ariakit/react': 0.3.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@babel/runtime': 7.25.0 - '@emotion/cache': 11.11.0 - '@emotion/css': 11.11.2 - '@emotion/react': 11.11.1(@types/react@17.0.71)(react@17.0.2) - '@emotion/serialize': 1.1.2 - '@emotion/styled': 11.11.0(@emotion/react@11.11.1(@types/react@17.0.71)(react@17.0.2))(@types/react@17.0.71)(react@17.0.2) - '@emotion/utils': 1.2.1 - '@floating-ui/react-dom': 2.0.4(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@radix-ui/react-dropdown-menu': 2.0.4(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@types/gradient-parser': 0.1.3 - '@types/highlight-words-core': 1.2.1 - '@use-gesture/react': 10.3.0(react@17.0.2) - '@wordpress/a11y': 3.47.0 - '@wordpress/compose': 6.24.0(react@17.0.2) - '@wordpress/date': 4.47.0 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 - '@wordpress/element': 5.34.0 - '@wordpress/escape-html': 2.47.0 - '@wordpress/hooks': 3.57.0 - '@wordpress/html-entities': 3.47.0 - '@wordpress/i18n': 4.54.0 - '@wordpress/icons': 9.48.0 - '@wordpress/is-shallow-equal': 4.47.0 - '@wordpress/keycodes': 3.57.0 - '@wordpress/primitives': 3.45.0 - '@wordpress/private-apis': 0.29.0 - '@wordpress/rich-text': 6.24.0(react@17.0.2) - '@wordpress/warning': 2.47.0 - change-case: 4.1.2 - classnames: 2.3.2 - colord: 2.9.3 - date-fns: 2.30.0 - deepmerge: 4.3.1 - dom-scroll-into-view: 1.2.1 - downshift: 6.1.12(react@17.0.2) - fast-deep-equal: 3.1.3 - framer-motion: 10.16.16(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - gradient-parser: 0.1.5 - highlight-words-core: 1.2.2 - is-plain-object: 5.0.0 - memize: 2.1.0 - path-to-regexp: 6.2.1 - re-resizable: 6.9.11(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - react: 17.0.2 - react-colorful: 5.6.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - react-dom: 17.0.2(react@17.0.2) - reakit: 1.3.11(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - remove-accents: 0.5.0 - use-lilius: 2.0.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - uuid: 9.0.1 - valtio: 1.7.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(babel-plugin-macros@3.1.0)(react@17.0.2) - transitivePeerDependencies: - - '@babel/helper-module-imports' - - '@babel/types' - - '@types/react' - - aslemammad-vite-plugin-macro - - babel-plugin-macros - - supports-color - - vite - '@wordpress/components@25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@ariakit/react': 0.3.14(react-dom@17.0.2(react@17.0.2))(react@17.0.2) @@ -40078,7 +39851,7 @@ snapshots: '@floating-ui/react-dom': 2.0.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@types/gradient-parser': 0.1.3 '@types/highlight-words-core': 1.2.1 - '@use-gesture/react': 10.3.0(react@17.0.2) + '@use-gesture/react': 10.3.1(react@17.0.2) '@wordpress/a11y': 3.57.0 '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/date': 4.57.0 @@ -40141,7 +39914,7 @@ snapshots: '@floating-ui/react-dom': 2.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/gradient-parser': 0.1.3 '@types/highlight-words-core': 1.2.1 - '@use-gesture/react': 10.3.0(react@18.3.1) + '@use-gesture/react': 10.3.1(react@18.3.1) '@wordpress/a11y': 3.57.0 '@wordpress/compose': 6.34.0(react@18.3.1) '@wordpress/date': 4.57.0 @@ -40266,7 +40039,7 @@ snapshots: '@floating-ui/react-dom': 2.0.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@types/gradient-parser': 0.1.3 '@types/highlight-words-core': 1.2.1 - '@use-gesture/react': 10.3.0(react@17.0.2) + '@use-gesture/react': 10.3.1(react@17.0.2) '@wordpress/a11y': 3.57.0 '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/date': 4.57.0 @@ -40308,6 +40081,61 @@ snapshots: - '@types/react' - supports-color + '@wordpress/components@28.6.0(@emotion/is-prop-valid@1.2.1)(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': + dependencies: + '@ariakit/react': 0.4.10(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@babel/runtime': 7.25.0 + '@emotion/cache': 11.11.0 + '@emotion/css': 11.11.2 + '@emotion/react': 11.11.1(@types/react@17.0.71)(react@17.0.2) + '@emotion/serialize': 1.1.2 + '@emotion/styled': 11.11.0(@emotion/react@11.11.1(@types/react@17.0.71)(react@17.0.2))(@types/react@17.0.71)(react@17.0.2) + '@emotion/utils': 1.2.1 + '@floating-ui/react-dom': 2.0.9(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@types/gradient-parser': 0.1.3 + '@types/highlight-words-core': 1.2.1 + '@use-gesture/react': 10.3.1(react@17.0.2) + '@wordpress/a11y': 4.6.0 + '@wordpress/compose': 7.6.0(react@17.0.2) + '@wordpress/date': 5.6.0 + '@wordpress/deprecated': 4.6.0 + '@wordpress/dom': 4.6.0 + '@wordpress/element': 6.6.0 + '@wordpress/escape-html': 3.6.0 + '@wordpress/hooks': 4.6.0 + '@wordpress/html-entities': 4.6.0 + '@wordpress/i18n': 5.6.0 + '@wordpress/icons': 10.6.0(react@17.0.2) + '@wordpress/is-shallow-equal': 5.6.0 + '@wordpress/keycodes': 4.6.0 + '@wordpress/primitives': 4.6.0(react@17.0.2) + '@wordpress/private-apis': 1.6.0 + '@wordpress/rich-text': 7.6.0(react@17.0.2) + '@wordpress/warning': 3.6.0 + change-case: 4.1.2 + clsx: 2.1.1 + colord: 2.9.3 + date-fns: 3.6.0 + deepmerge: 4.3.1 + fast-deep-equal: 3.1.3 + framer-motion: 11.3.30(@emotion/is-prop-valid@1.2.1)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + gradient-parser: 0.1.5 + highlight-words-core: 1.2.2 + is-plain-object: 5.0.0 + memize: 2.1.0 + path-to-regexp: 6.2.1 + re-resizable: 6.9.11(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + react: 17.0.2 + react-colorful: 5.6.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + react-dom: 17.0.2(react@17.0.2) + remove-accents: 0.5.0 + use-lilius: 2.0.5(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + uuid: 9.0.1 + transitivePeerDependencies: + - '@emotion/is-prop-valid' + - '@types/react' + - supports-color + '@wordpress/compose@3.25.3(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -40331,8 +40159,8 @@ snapshots: '@babel/runtime': 7.25.0 '@types/lodash': 4.14.149 '@types/mousetrap': 1.6.15 - '@wordpress/deprecated': 3.41.0 - '@wordpress/dom': 3.27.0 + '@wordpress/deprecated': 3.6.1 + '@wordpress/dom': 3.6.1 '@wordpress/element': 3.2.0 '@wordpress/is-shallow-equal': 4.24.0 '@wordpress/keycodes': 3.47.0 @@ -40350,7 +40178,7 @@ snapshots: '@babel/runtime': 7.25.0 '@types/mousetrap': 1.6.15 '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/dom': 3.27.0 '@wordpress/element': 4.20.0 '@wordpress/is-shallow-equal': 4.47.0 '@wordpress/keycodes': 3.47.0 @@ -40366,7 +40194,7 @@ snapshots: '@babel/runtime': 7.25.0 '@types/mousetrap': 1.6.15 '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/dom': 3.27.0 '@wordpress/element': 4.20.0 '@wordpress/is-shallow-equal': 4.47.0 '@wordpress/keycodes': 3.47.0 @@ -40383,7 +40211,7 @@ snapshots: '@types/lodash': 4.14.202 '@types/mousetrap': 1.6.15 '@wordpress/deprecated': 3.6.1 - '@wordpress/dom': 3.27.0 + '@wordpress/dom': 3.6.1 '@wordpress/element': 4.4.1 '@wordpress/is-shallow-equal': 4.24.0 '@wordpress/keycodes': 3.6.1 @@ -40397,7 +40225,7 @@ snapshots: '@wordpress/compose@5.5.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.25.0 '@types/lodash': 4.14.202 '@types/mousetrap': 1.6.15 '@wordpress/deprecated': 3.41.0 @@ -40415,7 +40243,7 @@ snapshots: '@wordpress/compose@5.5.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.25.0 '@types/lodash': 4.14.202 '@types/mousetrap': 1.6.15 '@wordpress/deprecated': 3.41.0 @@ -40435,8 +40263,8 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 '@types/mousetrap': 1.6.15 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/deprecated': 3.57.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.34.0 '@wordpress/is-shallow-equal': 4.47.0 '@wordpress/keycodes': 3.47.0 @@ -40452,8 +40280,8 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 '@types/mousetrap': 1.6.15 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/deprecated': 3.57.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.34.0 '@wordpress/is-shallow-equal': 4.47.0 '@wordpress/keycodes': 3.47.0 @@ -40499,12 +40327,29 @@ snapshots: react: 18.3.1 use-memo-one: 1.1.3(react@18.3.1) + '@wordpress/compose@7.6.0(react@17.0.2)': + dependencies: + '@babel/runtime': 7.25.0 + '@types/mousetrap': 1.6.15 + '@wordpress/deprecated': 4.6.0 + '@wordpress/dom': 4.6.0 + '@wordpress/element': 6.6.0 + '@wordpress/is-shallow-equal': 5.6.0 + '@wordpress/keycodes': 4.6.0 + '@wordpress/priority-queue': 3.6.0 + '@wordpress/undo-manager': 1.6.0 + change-case: 4.1.2 + clipboard: 2.0.11 + mousetrap: 1.6.5 + react: 17.0.2 + use-memo-one: 1.1.3(react@17.0.2) + '@wordpress/core-commands@0.7.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 '@wordpress/commands': 0.9.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/core-data': 6.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.22.0 '@wordpress/i18n': 4.47.0 '@wordpress/icons': 9.36.0 @@ -40707,6 +40552,25 @@ snapshots: '@wordpress/deprecated': 3.41.0 react: 17.0.2 + '@wordpress/data@10.6.0(react@17.0.2)': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/compose': 7.6.0(react@17.0.2) + '@wordpress/deprecated': 4.6.0 + '@wordpress/element': 6.6.0 + '@wordpress/is-shallow-equal': 5.6.0 + '@wordpress/priority-queue': 3.6.0 + '@wordpress/private-apis': 1.6.0 + '@wordpress/redux-routine': 5.6.0(redux@4.2.1) + deepmerge: 4.3.1 + equivalent-key-map: 0.2.2 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + react: 17.0.2 + redux: 4.2.1 + rememo: 4.0.2 + use-memo-one: 1.1.3(react@17.0.2) + '@wordpress/data@4.27.3(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -40733,8 +40597,8 @@ snapshots: '@wordpress/deprecated': 3.6.1 '@wordpress/element': 3.2.0 '@wordpress/is-shallow-equal': 4.24.0 - '@wordpress/priority-queue': 2.47.0 - '@wordpress/redux-routine': 4.47.0(redux@4.2.1) + '@wordpress/priority-queue': 2.57.0 + '@wordpress/redux-routine': 4.57.0(redux@4.2.1) equivalent-key-map: 0.2.2 is-promise: 4.0.0 lodash: 4.17.21 @@ -40747,7 +40611,7 @@ snapshots: '@wordpress/data@6.15.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/compose': 5.20.0(react@17.0.2) '@wordpress/deprecated': 3.41.0 '@wordpress/element': 4.20.0 @@ -40817,7 +40681,7 @@ snapshots: '@wordpress/data@7.6.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/compose': 5.20.0(react@17.0.2) '@wordpress/deprecated': 3.41.0 '@wordpress/element': 4.20.0 @@ -40835,7 +40699,7 @@ snapshots: '@wordpress/data@7.6.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/compose': 5.20.0(react@18.3.1) '@wordpress/deprecated': 3.41.0 '@wordpress/element': 4.20.0 @@ -40927,6 +40791,28 @@ snapshots: rememo: 4.0.2 use-memo-one: 1.1.3(react@18.3.1) + '@wordpress/dataviews@4.2.0(@emotion/is-prop-valid@1.2.1)(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': + dependencies: + '@ariakit/react': 0.4.10(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@babel/runtime': 7.25.0 + '@wordpress/components': 28.6.0(@emotion/is-prop-valid@1.2.1)(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@wordpress/compose': 7.6.0(react@17.0.2) + '@wordpress/data': 10.6.0(react@17.0.2) + '@wordpress/element': 6.6.0 + '@wordpress/i18n': 5.6.0 + '@wordpress/icons': 10.6.0(react@17.0.2) + '@wordpress/primitives': 4.6.0(react@17.0.2) + '@wordpress/private-apis': 1.6.0 + '@wordpress/warning': 3.6.0 + clsx: 2.1.1 + react: 17.0.2 + remove-accents: 0.5.0 + transitivePeerDependencies: + - '@emotion/is-prop-valid' + - '@types/react' + - react-dom + - supports-color + '@wordpress/date@4.44.0': dependencies: '@babel/runtime': 7.23.5 @@ -40934,13 +40820,6 @@ snapshots: moment: 2.29.4 moment-timezone: 0.5.43 - '@wordpress/date@4.47.0': - dependencies: - '@babel/runtime': 7.25.0 - '@wordpress/deprecated': 3.47.0 - moment: 2.29.4 - moment-timezone: 0.5.43 - '@wordpress/date@4.57.0': dependencies: '@babel/runtime': 7.25.0 @@ -40954,6 +40833,13 @@ snapshots: moment: 2.29.4 moment-timezone: 0.5.43 + '@wordpress/date@5.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/deprecated': 4.6.0 + moment: 2.29.4 + moment-timezone: 0.5.43 + '@wordpress/dependency-extraction-webpack-plugin@2.9.0(webpack@4.47.0(webpack-cli@3.3.12))': dependencies: json2php: 0.0.4 @@ -41015,6 +40901,11 @@ snapshots: '@babel/runtime': 7.23.5 '@wordpress/hooks': 3.6.1 + '@wordpress/deprecated@4.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/hooks': 4.6.0 + '@wordpress/dom-ready@3.27.0': dependencies: '@babel/runtime': 7.23.5 @@ -41031,6 +40922,10 @@ snapshots: dependencies: '@babel/runtime': 7.23.5 + '@wordpress/dom-ready@4.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/dom@2.18.0': dependencies: '@babel/runtime': 7.25.0 @@ -41041,11 +40936,6 @@ snapshots: '@babel/runtime': 7.23.5 '@wordpress/deprecated': 3.41.0 - '@wordpress/dom@3.47.0': - dependencies: - '@babel/runtime': 7.25.0 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom@3.57.0': dependencies: '@babel/runtime': 7.25.0 @@ -41056,6 +40946,11 @@ snapshots: '@babel/runtime': 7.23.5 lodash: 4.17.21 + '@wordpress/dom@4.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/deprecated': 4.6.0 + '@wordpress/e2e-test-utils-playwright@1.0.1(@playwright/test@1.46.1)(encoding@0.1.13)(typescript@5.3.2)': dependencies: '@playwright/test': 1.46.1 @@ -41134,7 +41029,7 @@ snapshots: '@wordpress/e2e-test-utils@4.16.1(encoding@0.1.13)(jest@25.5.4)(puppeteer@2.1.1)(react-native@0.73.0(@babel/core@7.23.5)(@babel/preset-env@7.23.6(@babel/core@7.23.5))(encoding@0.1.13)(react@18.3.1))': dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.23.5 '@wordpress/keycodes': 2.19.3 '@wordpress/url': 2.22.2(react-native@0.73.0(@babel/core@7.23.5)(@babel/preset-env@7.23.6(@babel/core@7.23.5))(encoding@0.1.13)(react@18.3.1)) jest: 25.5.4 @@ -41160,7 +41055,7 @@ snapshots: '@wordpress/e2e-test-utils@4.16.1(encoding@0.1.13)(jest@29.7.0(@types/node@22.4.0)(babel-plugin-macros@3.1.0)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.4.0)(typescript@5.3.3)))(puppeteer@17.1.3(encoding@0.1.13))(react-native@0.73.0(@babel/core@7.12.9)(@babel/preset-env@7.12.7(@babel/core@7.12.9))(encoding@0.1.13)(react@18.3.1))': dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.23.5 '@wordpress/keycodes': 2.19.3 '@wordpress/url': 2.22.2(react-native@0.73.0(@babel/core@7.12.9)(@babel/preset-env@7.12.7(@babel/core@7.12.9))(encoding@0.1.13)(react@18.3.1)) jest: 29.7.0(@types/node@22.4.0)(babel-plugin-macros@3.1.0)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@22.4.0)(typescript@5.3.3)) @@ -41264,7 +41159,7 @@ snapshots: '@wordpress/element': 4.4.1 '@wordpress/hooks': 3.6.1 '@wordpress/i18n': 4.6.1 - '@wordpress/icons': 8.2.3 + '@wordpress/icons': 8.4.0 '@wordpress/interface': 4.5.6(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react-with-direction@1.4.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2) '@wordpress/keyboard-shortcuts': 3.4.1(react@17.0.2) '@wordpress/keycodes': 3.6.1 @@ -41288,36 +41183,36 @@ snapshots: '@wordpress/edit-site@5.15.0(patch_hash=6y3l6gxu33zybfmvbjd23dtqda)(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@preact/signals-core@1.5.1)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@babel/runtime': 7.23.5 - '@wordpress/a11y': 3.47.0 + '@babel/runtime': 7.25.0 + '@wordpress/a11y': 3.57.0 '@wordpress/api-fetch': 6.44.0 '@wordpress/block-editor': 12.15.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/block-library': 8.24.1(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@preact/signals-core@1.5.1)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/blocks': 12.24.0(react@17.0.2) '@wordpress/commands': 0.9.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/components': 25.13.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/compose': 6.24.0(react@17.0.2) + '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/core-commands': 0.7.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/core-data': 6.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/date': 4.44.0 '@wordpress/deprecated': 3.41.0 - '@wordpress/dom': 3.47.0 + '@wordpress/dom': 3.57.0 '@wordpress/editor': 13.24.1(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/element': 5.22.0 - '@wordpress/escape-html': 2.47.0 + '@wordpress/escape-html': 2.57.0 '@wordpress/hooks': 3.57.0 - '@wordpress/html-entities': 3.47.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/html-entities': 3.57.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.36.0 '@wordpress/interface': 5.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/keyboard-shortcuts': 4.24.0(react@17.0.2) - '@wordpress/keycodes': 3.47.0 + '@wordpress/keycodes': 3.57.0 '@wordpress/media-utils': 4.38.0 '@wordpress/notices': 4.15.0(react@17.0.2) '@wordpress/plugins': 6.15.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/preferences': 3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/primitives': 3.45.0 + '@wordpress/primitives': 3.55.0 '@wordpress/private-apis': 0.20.0 '@wordpress/reusable-blocks': 4.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/router': 0.7.0(react@17.0.2) @@ -41369,7 +41264,7 @@ snapshots: '@wordpress/hooks': 3.6.1 '@wordpress/html-entities': 3.6.1 '@wordpress/i18n': 4.6.1 - '@wordpress/icons': 8.2.3 + '@wordpress/icons': 8.4.0 '@wordpress/keyboard-shortcuts': 3.4.1(react@17.0.2) '@wordpress/keycodes': 3.6.1 '@wordpress/media-utils': 3.4.1 @@ -41395,22 +41290,22 @@ snapshots: '@wordpress/editor@13.24.1(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 + '@wordpress/a11y': 3.57.0 '@wordpress/api-fetch': 6.44.0 '@wordpress/blob': 3.47.0 '@wordpress/block-editor': 12.15.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/blocks': 12.24.0(react@17.0.2) '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/compose': 6.24.0(react@17.0.2) + '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/core-data': 6.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) - '@wordpress/date': 4.47.0 - '@wordpress/deprecated': 3.47.0 - '@wordpress/dom': 3.47.0 + '@wordpress/data': 9.27.0(react@17.0.2) + '@wordpress/date': 4.57.0 + '@wordpress/deprecated': 3.57.0 + '@wordpress/dom': 3.57.0 '@wordpress/element': 5.34.0 '@wordpress/hooks': 3.57.0 - '@wordpress/html-entities': 3.47.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/html-entities': 3.57.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.48.0 '@wordpress/keyboard-shortcuts': 4.24.0(react@17.0.2) '@wordpress/keycodes': 3.57.0 @@ -41420,7 +41315,7 @@ snapshots: '@wordpress/preferences': 3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/private-apis': 0.29.0 '@wordpress/reusable-blocks': 4.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/rich-text': 6.24.0(react@17.0.2) + '@wordpress/rich-text': 6.34.0(react@17.0.2) '@wordpress/server-side-render': 4.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/url': 3.48.0 '@wordpress/wordcount': 3.47.0 @@ -41517,6 +41412,17 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + '@wordpress/element@6.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@types/react': 17.0.71 + '@types/react-dom': 18.3.0 + '@wordpress/escape-html': 3.6.0 + change-case: 4.1.2 + is-plain-object: 5.0.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + '@wordpress/env@10.5.0': dependencies: chalk: 4.1.2 @@ -41546,6 +41452,10 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 + '@wordpress/escape-html@3.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/eslint-plugin@12.9.0(@babel/core@7.24.7)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.56.0(eslint@8.55.0)(typescript@5.3.2))(eslint-import-resolver-webpack@0.13.2)(eslint-plugin-import@2.28.1)(eslint@8.55.0))(eslint-import-resolver-webpack@0.13.2(eslint-plugin-import@2.28.1)(webpack@5.91.0(@swc/core@1.3.100)(esbuild@0.18.20)(webpack-cli@5.1.4)))(eslint@8.55.0)(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.2)))(typescript@5.3.2)(wp-prettier@2.6.2)': dependencies: '@babel/core': 7.24.7 @@ -41715,13 +41625,13 @@ snapshots: '@wordpress/hooks@3.57.0': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/hooks@3.6.1': dependencies: '@babel/runtime': 7.24.7 - '@wordpress/hooks@4.4.0': + '@wordpress/hooks@4.6.0': dependencies: '@babel/runtime': 7.25.0 @@ -41741,6 +41651,10 @@ snapshots: dependencies: '@babel/runtime': 7.23.5 + '@wordpress/html-entities@4.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/i18n@3.20.0': dependencies: '@babel/runtime': 7.25.0 @@ -41769,15 +41683,6 @@ snapshots: sprintf-js: 1.1.3 tannin: 1.2.0 - '@wordpress/i18n@4.54.0': - dependencies: - '@babel/runtime': 7.25.0 - '@wordpress/hooks': 3.57.0 - gettext-parser: 1.4.0 - memize: 2.1.0 - sprintf-js: 1.1.3 - tannin: 1.2.0 - '@wordpress/i18n@4.57.0': dependencies: '@babel/runtime': 7.25.0 @@ -41800,12 +41705,29 @@ snapshots: '@wordpress/i18n@5.0.1': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/hooks': 4.4.0 + '@wordpress/hooks': 4.6.0 gettext-parser: 1.4.0 memize: 2.1.0 sprintf-js: 1.1.3 tannin: 1.2.0 + '@wordpress/i18n@5.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/hooks': 4.6.0 + gettext-parser: 1.4.0 + memize: 2.1.0 + sprintf-js: 1.1.3 + tannin: 1.2.0 + + '@wordpress/icons@10.6.0(react@17.0.2)': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/element': 6.6.0 + '@wordpress/primitives': 4.6.0(react@17.0.2) + transitivePeerDependencies: + - react + '@wordpress/icons@4.1.0': dependencies: '@babel/runtime': 7.25.0 @@ -41836,12 +41758,6 @@ snapshots: '@wordpress/element': 5.22.0 '@wordpress/primitives': 3.45.0 - '@wordpress/icons@9.38.0': - dependencies: - '@babel/runtime': 7.25.0 - '@wordpress/element': 5.34.0 - '@wordpress/primitives': 3.45.0 - '@wordpress/icons@9.48.0': dependencies: '@babel/runtime': 7.25.0 @@ -41867,7 +41783,7 @@ snapshots: '@wordpress/deprecated': 3.6.1 '@wordpress/element': 4.4.1 '@wordpress/i18n': 4.6.1 - '@wordpress/icons': 8.2.3 + '@wordpress/icons': 8.4.0 '@wordpress/plugins': 4.4.3(react@17.0.2) '@wordpress/preferences': 1.2.5(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react-with-direction@1.4.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2) '@wordpress/viewport': 4.20.0(react@17.0.2) @@ -41882,15 +41798,15 @@ snapshots: '@wordpress/interface@5.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@babel/runtime': 7.23.5 - '@wordpress/a11y': 3.47.0 - '@wordpress/components': 25.13.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/compose': 6.24.0(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) - '@wordpress/deprecated': 3.47.0 - '@wordpress/element': 5.24.0 - '@wordpress/i18n': 4.47.0 - '@wordpress/icons': 9.38.0 + '@babel/runtime': 7.25.0 + '@wordpress/a11y': 3.57.0 + '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@wordpress/compose': 6.34.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) + '@wordpress/deprecated': 3.57.0 + '@wordpress/element': 5.34.0 + '@wordpress/i18n': 4.57.0 + '@wordpress/icons': 9.48.0 '@wordpress/plugins': 6.15.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/preferences': 3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/viewport': 5.24.0(react@17.0.2) @@ -41922,6 +41838,10 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 + '@wordpress/is-shallow-equal@5.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/jest-console@3.10.0(jest@25.5.4)': dependencies: '@babel/runtime': 7.25.0 @@ -42078,7 +41998,7 @@ snapshots: '@wordpress/keyboard-shortcuts@3.20.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/data': 7.6.0(react@17.0.2) '@wordpress/element': 4.20.0 '@wordpress/keycodes': 3.47.0 @@ -42108,7 +42028,7 @@ snapshots: '@wordpress/keyboard-shortcuts@4.24.0(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.34.0 '@wordpress/keycodes': 3.57.0 react: 17.0.2 @@ -42117,7 +42037,7 @@ snapshots: '@wordpress/keyboard-shortcuts@4.24.0(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/data': 9.17.0(react@18.3.1) + '@wordpress/data': 9.27.0(react@18.3.1) '@wordpress/element': 5.34.0 '@wordpress/keycodes': 3.57.0 react: 18.3.1 @@ -42151,6 +42071,11 @@ snapshots: '@babel/runtime': 7.25.0 '@wordpress/i18n': 5.0.1 + '@wordpress/keycodes@4.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/i18n': 5.6.0 + '@wordpress/lazy-import@1.34.0': dependencies: execa: 4.1.0 @@ -42176,21 +42101,21 @@ snapshots: '@wordpress/notices@3.12.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/a11y': 3.47.0 '@wordpress/data': 6.15.0(react@17.0.2) react: 17.0.2 '@wordpress/notices@3.12.0(react@18.3.1)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/a11y': 3.47.0 '@wordpress/data': 6.15.0(react@18.3.1) react: 18.3.1 '@wordpress/notices@3.31.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/a11y': 3.47.0 '@wordpress/data': 9.17.0(react@17.0.2) transitivePeerDependencies: @@ -42207,15 +42132,15 @@ snapshots: '@wordpress/notices@4.15.0(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/a11y': 3.57.0 + '@wordpress/data': 9.27.0(react@17.0.2) react: 17.0.2 '@wordpress/notices@4.15.0(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 - '@wordpress/data': 9.17.0(react@18.3.1) + '@wordpress/a11y': 3.57.0 + '@wordpress/data': 9.27.0(react@18.3.1) react: 18.3.1 '@wordpress/npm-package-json-lint-config@3.1.0(npm-package-json-lint@5.4.2)': @@ -42237,7 +42162,7 @@ snapshots: '@wordpress/core-data': 6.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.34.0 - '@wordpress/html-entities': 3.47.0 + '@wordpress/html-entities': 3.57.0 '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.48.0 '@wordpress/notices': 4.15.0(react@17.0.2) @@ -42281,11 +42206,11 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/compose': 6.24.0(react@17.0.2) + '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/element': 5.34.0 '@wordpress/hooks': 3.57.0 '@wordpress/icons': 9.48.0 - '@wordpress/is-shallow-equal': 4.47.0 + '@wordpress/is-shallow-equal': 4.57.0 memize: 2.1.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -42355,7 +42280,7 @@ snapshots: '@wordpress/preferences@3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 + '@wordpress/a11y': 3.57.0 '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.34.0 @@ -42376,7 +42301,7 @@ snapshots: '@wordpress/preferences@3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 + '@wordpress/a11y': 3.57.0 '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': 9.27.0(react@18.3.1) '@wordpress/element': 5.34.0 @@ -42446,6 +42371,13 @@ snapshots: '@wordpress/element': 5.34.0 classnames: 2.3.2 + '@wordpress/primitives@4.6.0(react@17.0.2)': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/element': 6.6.0 + clsx: 2.1.1 + react: 17.0.2 + '@wordpress/priority-queue@1.11.2': dependencies: '@babel/runtime': 7.25.0 @@ -42460,13 +42392,18 @@ snapshots: '@babel/runtime': 7.25.0 requestidlecallback: 0.3.0 + '@wordpress/priority-queue@3.6.0': + dependencies: + '@babel/runtime': 7.25.0 + requestidlecallback: 0.3.0 + '@wordpress/private-apis@0.20.0': dependencies: '@babel/runtime': 7.25.0 '@wordpress/private-apis@0.29.0': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/private-apis@0.32.0': dependencies: @@ -42514,6 +42451,14 @@ snapshots: redux: 4.2.1 rungen: 0.3.2 + '@wordpress/redux-routine@5.6.0(redux@4.2.1)': + dependencies: + '@babel/runtime': 7.25.0 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + redux: 4.2.1 + rungen: 0.3.2 + '@wordpress/reusable-blocks@3.20.0(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@wordpress/block-editor': 10.5.0(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) @@ -42539,9 +42484,9 @@ snapshots: '@wordpress/blocks': 12.24.0(react@17.0.2) '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/core-data': 6.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.34.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.48.0 '@wordpress/notices': 4.15.0(react@17.0.2) '@wordpress/private-apis': 0.29.0 @@ -42564,7 +42509,7 @@ snapshots: '@babel/runtime': 7.25.0 '@wordpress/compose': 4.2.0(react@18.3.1) '@wordpress/data': 5.2.0(react@18.3.1)(redux@4.2.1) - '@wordpress/dom': 3.27.0 + '@wordpress/dom': 3.6.1 '@wordpress/element': 3.2.0 '@wordpress/escape-html': 2.57.0 '@wordpress/is-shallow-equal': 4.24.0 @@ -42637,36 +42582,6 @@ snapshots: react: 18.3.1 rememo: 3.0.0 - '@wordpress/rich-text@6.24.0(react@17.0.2)': - dependencies: - '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 - '@wordpress/compose': 6.34.0(react@17.0.2) - '@wordpress/data': 9.27.0(react@17.0.2) - '@wordpress/deprecated': 3.47.0 - '@wordpress/element': 5.34.0 - '@wordpress/escape-html': 2.57.0 - '@wordpress/i18n': 4.57.0 - '@wordpress/keycodes': 3.57.0 - memize: 2.1.0 - react: 17.0.2 - rememo: 4.0.2 - - '@wordpress/rich-text@6.24.0(react@18.3.1)': - dependencies: - '@babel/runtime': 7.25.0 - '@wordpress/a11y': 3.47.0 - '@wordpress/compose': 6.34.0(react@18.3.1) - '@wordpress/data': 9.27.0(react@18.3.1) - '@wordpress/deprecated': 3.47.0 - '@wordpress/element': 5.34.0 - '@wordpress/escape-html': 2.57.0 - '@wordpress/i18n': 4.57.0 - '@wordpress/keycodes': 3.57.0 - memize: 2.1.0 - react: 18.3.1 - rememo: 4.0.2 - '@wordpress/rich-text@6.34.0(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -42695,9 +42610,23 @@ snapshots: memize: 2.1.0 react: 18.3.1 + '@wordpress/rich-text@7.6.0(react@17.0.2)': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/a11y': 4.6.0 + '@wordpress/compose': 7.6.0(react@17.0.2) + '@wordpress/data': 10.6.0(react@17.0.2) + '@wordpress/deprecated': 4.6.0 + '@wordpress/element': 6.6.0 + '@wordpress/escape-html': 3.6.0 + '@wordpress/i18n': 5.6.0 + '@wordpress/keycodes': 4.6.0 + memize: 2.1.0 + react: 17.0.2 + '@wordpress/router@0.7.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.23.5 + '@babel/runtime': 7.25.0 '@wordpress/element': 5.22.0 '@wordpress/private-apis': 0.20.0 '@wordpress/url': 3.48.0 @@ -43019,7 +42948,7 @@ snapshots: '@wordpress/server-side-render@3.10.0(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react-with-direction@1.4.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2)': dependencies: - '@babel/runtime': 7.23.5 + '@babel/runtime': 7.25.0 '@wordpress/api-fetch': 6.21.0 '@wordpress/blocks': 11.21.0(react@17.0.2) '@wordpress/components': 19.17.0(@types/react@17.0.71)(react-dom@17.0.2(react@17.0.2))(react-with-direction@1.4.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(react@17.0.2) @@ -43084,7 +43013,7 @@ snapshots: '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/data': 9.27.0(react@17.0.2) - '@wordpress/deprecated': 3.47.0 + '@wordpress/deprecated': 3.57.0 '@wordpress/element': 5.34.0 '@wordpress/i18n': 4.57.0 '@wordpress/url': 3.48.0 @@ -43107,7 +43036,7 @@ snapshots: '@wordpress/style-engine@0.15.0': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 lodash: 4.17.21 '@wordpress/style-engine@0.2.0': @@ -43177,7 +43106,12 @@ snapshots: '@wordpress/undo-manager@0.7.0': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/is-shallow-equal': 4.47.0 + '@wordpress/is-shallow-equal': 4.57.0 + + '@wordpress/undo-manager@1.6.0': + dependencies: + '@babel/runtime': 7.25.0 + '@wordpress/is-shallow-equal': 5.6.0 '@wordpress/url@2.22.2(react-native@0.73.0(@babel/core@7.12.9)(@babel/preset-env@7.12.7(@babel/core@7.12.9))(encoding@0.1.13)(react@18.3.1))': dependencies: @@ -43225,7 +43159,7 @@ snapshots: '@wordpress/viewport@4.20.0(react@17.0.2)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@wordpress/compose': 5.20.0(react@17.0.2) '@wordpress/data': 7.6.0(react@17.0.2) react: 17.0.2 @@ -43241,8 +43175,8 @@ snapshots: '@wordpress/viewport@5.24.0(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 - '@wordpress/compose': 6.24.0(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/compose': 6.34.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.34.0 react: 17.0.2 @@ -43254,6 +43188,8 @@ snapshots: '@wordpress/warning@2.6.1': {} + '@wordpress/warning@3.6.0': {} + '@wordpress/widgets@3.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@babel/runtime': 7.25.0 @@ -43261,11 +43197,11 @@ snapshots: '@wordpress/block-editor': 12.15.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@wordpress/blocks': 12.24.0(react@17.0.2) '@wordpress/components': 25.16.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/compose': 6.24.0(react@17.0.2) + '@wordpress/compose': 6.34.0(react@17.0.2) '@wordpress/core-data': 6.24.0(@babel/helper-module-imports@7.24.7)(@babel/types@7.25.2)(@types/react@17.0.71)(babel-plugin-macros@3.1.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - '@wordpress/data': 9.17.0(react@17.0.2) + '@wordpress/data': 9.27.0(react@17.0.2) '@wordpress/element': 5.34.0 - '@wordpress/i18n': 4.47.0 + '@wordpress/i18n': 4.57.0 '@wordpress/icons': 9.48.0 '@wordpress/notices': 4.15.0(react@17.0.2) classnames: 2.3.2 @@ -46817,7 +46753,7 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 date-fns@3.6.0: {} @@ -47739,7 +47675,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.56.0(eslint@8.55.0)(typescript@5.3.2))(eslint-import-resolver-webpack@0.13.2)(eslint-plugin-import@2.28.1)(eslint@8.55.0): dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.15.0 eslint: 8.55.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.56.0(eslint@8.55.0)(typescript@5.3.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.56.0(eslint@8.55.0)(typescript@5.3.2))(eslint-import-resolver-webpack@0.13.2)(eslint-plugin-import@2.28.1)(eslint@8.55.0))(eslint-import-resolver-webpack@0.13.2(eslint-plugin-import@2.28.1)(webpack@5.91.0(@swc/core@1.3.100)(esbuild@0.18.20)(webpack-cli@5.1.4)))(eslint@8.55.0) @@ -47756,7 +47692,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.55.0)(typescript@5.3.3))(eslint-import-resolver-webpack@0.13.8)(eslint-plugin-import@2.29.0)(eslint@8.55.0): dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.15.0 eslint: 8.55.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.55.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0(eslint@8.55.0)(typescript@5.3.3))(eslint-import-resolver-webpack@0.13.8)(eslint-plugin-import@2.29.0)(eslint@8.55.0))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.0)(webpack@5.89.0(webpack-cli@4.10.0)))(eslint@8.55.0) @@ -48109,7 +48045,7 @@ snapshots: eslint-plugin-jsx-a11y@6.8.0(eslint@8.55.0): dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 aria-query: 5.3.0 array-includes: 3.1.7 array.prototype.flatmap: 1.3.2 @@ -48442,7 +48378,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -49170,7 +49106,7 @@ snapshots: follow-redirects@1.15.6(debug@4.3.4): optionalDependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) follow-redirects@1.5.10: dependencies: @@ -49391,6 +49327,14 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + framer-motion@11.3.30(@emotion/is-prop-valid@1.2.1)(react-dom@17.0.2(react@17.0.2))(react@17.0.2): + dependencies: + tslib: 2.6.3 + optionalDependencies: + '@emotion/is-prop-valid': 1.2.1 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + framer-motion@6.5.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: '@motionone/dom': 10.12.0 @@ -52393,7 +52337,9 @@ snapshots: pretty-format: 24.9.0 throat: 4.1.0 transitivePeerDependencies: + - bufferutil - supports-color + - utf-8-validate jest-jasmine2@25.5.4: dependencies: @@ -54065,7 +54011,7 @@ snapshots: chalk: 5.2.0 cli-truncate: 3.1.0 commander: 10.0.1 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) execa: 7.2.0 lilconfig: 2.1.0 listr2: 5.0.8(enquirer@2.4.1) @@ -55369,7 +55315,7 @@ snapshots: dependencies: carlo: 0.9.46 chokidar: 3.5.3 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) isbinaryfile: 3.0.3 mime: 2.6.0 opn: 5.5.0 @@ -55897,7 +55843,7 @@ snapshots: '@oclif/plugin-warn-if-update-available': 2.1.1(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3) aws-sdk: 2.1515.0 concurrently: 7.6.0 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) find-yarn-workspace-root: 2.0.0 fs-extra: 8.1.0 github-slugger: 1.5.0 @@ -56525,7 +56471,7 @@ snapshots: polished@4.2.2: dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 popmotion@11.0.3: dependencies: @@ -57409,7 +57355,7 @@ snapshots: puppeteer-core@13.7.0(encoding@0.1.13): dependencies: cross-fetch: 3.1.5(encoding@0.1.13) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) devtools-protocol: 0.0.981744 extract-zip: 2.0.1 https-proxy-agent: 5.0.1 @@ -57448,7 +57394,7 @@ snapshots: '@puppeteer/browsers': 1.4.6(typescript@5.3.2) chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) cross-fetch: 4.0.0(encoding@0.1.13) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) devtools-protocol: 0.0.1147663 ws: 8.13.0 optionalDependencies: @@ -57464,7 +57410,7 @@ snapshots: '@puppeteer/browsers': 1.4.6(typescript@5.3.3) chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) cross-fetch: 4.0.0(encoding@0.1.13) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) devtools-protocol: 0.0.1147663 ws: 8.13.0 optionalDependencies: @@ -57480,7 +57426,7 @@ snapshots: '@puppeteer/browsers': 1.9.0 chromium-bidi: 0.5.1(devtools-protocol@0.0.1203626) cross-fetch: 4.0.0(encoding@0.1.13) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) devtools-protocol: 0.0.1203626 ws: 8.14.2 transitivePeerDependencies: @@ -57516,7 +57462,7 @@ snapshots: puppeteer@17.1.3(encoding@0.1.13): dependencies: cross-fetch: 3.1.5(encoding@0.1.13) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) devtools-protocol: 0.0.1036444 extract-zip: 2.0.1 https-proxy-agent: 5.0.1 @@ -57850,7 +57796,7 @@ snapshots: react-docgen-typescript-plugin@1.0.5(typescript@5.3.2)(webpack@5.91.0(@swc/core@1.3.100)(esbuild@0.18.20)(webpack-cli@5.1.4)): dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -58011,7 +57957,7 @@ snapshots: react-inspector@5.1.1(react@17.0.2): dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 is-dom: 1.1.0 prop-types: 15.8.1 react: 17.0.2 @@ -58399,7 +58345,7 @@ snapshots: react-select@3.2.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.0 '@emotion/cache': 10.0.29 '@emotion/core': 10.3.1(react@17.0.2) '@emotion/css': 10.0.27 @@ -59806,7 +59752,7 @@ snapshots: dependencies: '@kwsites/file-exists': 1.1.1 '@kwsites/promise-deferred': 1.1.1 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -60554,7 +60500,7 @@ snapshots: colord: 2.9.3 cosmiconfig: 7.1.0 css-functions-list: 3.2.1 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.4(supports-color@8.1.1) fast-glob: 3.3.2 fastest-levenshtein: 1.0.16 file-entry-cache: 6.0.1 @@ -61327,7 +61273,7 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.23.5) - ts-jest@29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3): + ts-jest@29.1.1(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@27.5.1(node-notifier@8.0.2)(ts-node@10.9.2(@swc/core@1.3.100)(@types/node@16.18.68)(typescript@5.3.3)))(typescript@5.3.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -61859,14 +61805,14 @@ snapshots: optionalDependencies: file-loader: 6.2.0(webpack@5.89.0(webpack-cli@4.10.0)) - url-loader@4.1.1(file-loader@6.2.0(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))))(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))): + url-loader@4.1.1(file-loader@6.2.0(webpack@4.47.0))(webpack@4.47.0): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 4.47.0(webpack-cli@3.3.12(webpack@5.89.0)) + webpack: 4.47.0 optionalDependencies: - file-loader: 6.2.0(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) + file-loader: 6.2.0(webpack@4.47.0) url-loader@4.1.1(file-loader@6.2.0(webpack@5.89.0(uglify-js@3.17.4)(webpack-cli@4.10.0)))(webpack@5.89.0(uglify-js@3.17.4)(webpack-cli@4.10.0)): dependencies: @@ -61877,14 +61823,14 @@ snapshots: optionalDependencies: file-loader: 6.2.0(webpack@5.89.0(uglify-js@3.17.4)(webpack-cli@4.10.0)) - url-loader@4.1.1(file-loader@6.2.0(webpack@5.89.0))(webpack@4.47.0): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.89.0(webpack-cli@3.3.12)))(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 4.47.0 + webpack: 4.47.0(webpack-cli@3.3.12(webpack@5.89.0)) optionalDependencies: - file-loader: 6.2.0(webpack@4.47.0) + file-loader: 6.2.0(webpack@4.47.0(webpack-cli@3.3.12(webpack@5.89.0))) url-loader@4.1.1(file-loader@6.2.0(webpack@5.91.0(@swc/core@1.3.100)(esbuild@0.18.20)(webpack-cli@5.1.4)))(webpack@5.91.0(@swc/core@1.3.100)(esbuild@0.18.20)(webpack-cli@4.10.0)): dependencies: From dec89a13111f5c8cf2bc6864677b63453bc0ef35 Mon Sep 17 00:00:00 2001 From: Seghir Nadir Date: Fri, 30 Aug 2024 18:24:53 +0100 Subject: [PATCH 169/185] Revert "Store API: Do not resume orders with `pending` status (#50531)" (#51067) * Revert "Store API: Do not resume orders with `pending` status (#50531)" This reverts commit 3170acd1b0d15338e14079e464d1eabf64096751. * Add changefile(s) from automation for the following project(s): woocommerce --------- Co-authored-by: github-actions --- plugins/woocommerce/changelog/51067-revert-50531 | 4 ++++ .../woocommerce/src/StoreApi/Utilities/DraftOrderTrait.php | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 plugins/woocommerce/changelog/51067-revert-50531 diff --git a/plugins/woocommerce/changelog/51067-revert-50531 b/plugins/woocommerce/changelog/51067-revert-50531 new file mode 100644 index 00000000000..e65258f8afe --- /dev/null +++ b/plugins/woocommerce/changelog/51067-revert-50531 @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak +Comment: This reverts an existing PR. + diff --git a/plugins/woocommerce/src/StoreApi/Utilities/DraftOrderTrait.php b/plugins/woocommerce/src/StoreApi/Utilities/DraftOrderTrait.php index 4e80f2695f8..dedc60ae418 100644 --- a/plugins/woocommerce/src/StoreApi/Utilities/DraftOrderTrait.php +++ b/plugins/woocommerce/src/StoreApi/Utilities/DraftOrderTrait.php @@ -60,9 +60,8 @@ trait DraftOrderTrait { return true; } - // Failed orders and those needing payment can be retried if the cart hasn't changed. - // Pending orders are excluded from this check since they may be awaiting an update from the payment processor. - if ( $order_object->needs_payment() && ! $order_object->has_status( 'pending' ) && $order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) { + // Pending and failed orders can be retried if the cart hasn't changed. + if ( $order_object->needs_payment() && $order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) { return true; } From 3def18623e9b2a8df170000f6f3dbfb07b8caab7 Mon Sep 17 00:00:00 2001 From: Fernando Marichal Date: Fri, 30 Aug 2024 17:47:20 -0300 Subject: [PATCH 170/185] Fix variation selector display issues on the front end (#51023) * Add woocommerce class to single-product * Add changelog * Fix chevron alignment --- .../assets/js/blocks/single-product/save.tsx | 4 +++- .../changelog/fix-47794_variation_selector_display | 4 ++++ .../woocommerce/client/legacy/css/woocommerce.scss | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 plugins/woocommerce/changelog/fix-47794_variation_selector_display diff --git a/plugins/woocommerce-blocks/assets/js/blocks/single-product/save.tsx b/plugins/woocommerce-blocks/assets/js/blocks/single-product/save.tsx index 0feb6d8f950..4c8f4ef2973 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/single-product/save.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/single-product/save.tsx @@ -4,7 +4,9 @@ import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; const Save = () => { - const blockProps = useBlockProps.save(); + const blockProps = useBlockProps.save( { + className: 'woocommerce', + } ); return (
        diff --git a/plugins/woocommerce/changelog/fix-47794_variation_selector_display b/plugins/woocommerce/changelog/fix-47794_variation_selector_display new file mode 100644 index 00000000000..84ebab4b1c5 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-47794_variation_selector_display @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Fix variation selector display issues on the front end #51023 diff --git a/plugins/woocommerce/client/legacy/css/woocommerce.scss b/plugins/woocommerce/client/legacy/css/woocommerce.scss index efd786f4d58..8c97759bf97 100644 --- a/plugins/woocommerce/client/legacy/css/woocommerce.scss +++ b/plugins/woocommerce/client/legacy/css/woocommerce.scss @@ -445,6 +445,18 @@ p.demo_store, min-width: 75%; display: inline-block; margin-right: 1em; + + /* We hide the default chevron because it cannot be directly modified. Instead, we add a custom chevron using a background image. */ + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + padding-right: 2em; + background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItY2hldnJvbi1kb3duIj48cG9seWxpbmUgcG9pbnRzPSI2IDkgMTIgMTUgMTggOSI+PC9wb2x5bGluZT48L3N2Zz4=) + no-repeat; + background-size: 16px; + -webkit-background-size: 16px; + background-position: calc(100% - 12px) 50%; + -webkit-background-position: calc(100% - 12px) 50%; } td.label { From 36ede651db8382c89abec14a4e5c31ac22de159a Mon Sep 17 00:00:00 2001 From: RJ <27843274+rjchow@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:38:22 +0800 Subject: [PATCH 171/185] add: sanitise query params in remote logging (PHP) (#51013) --- .../fix-remote-logger-sanitise-query-params | 4 + .../src/Internal/Logging/RemoteLogger.php | 50 +- .../src/Internal/Logging/RemoteLoggerTest.php | 1051 +++++++++-------- 3 files changed, 628 insertions(+), 477 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-remote-logger-sanitise-query-params diff --git a/plugins/woocommerce/changelog/fix-remote-logger-sanitise-query-params b/plugins/woocommerce/changelog/fix-remote-logger-sanitise-query-params new file mode 100644 index 00000000000..bf2342b18e0 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-remote-logger-sanitise-query-params @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Add query params masking to remote logger diff --git a/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php b/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php index 3bcb44f4c29..6daa928b46e 100644 --- a/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php +++ b/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php @@ -70,7 +70,7 @@ class RemoteLogger extends \WC_Log_Handler { 'wc_version' => WC()->version, 'php_version' => phpversion(), 'wp_version' => get_bloginfo( 'version' ), - 'request_uri' => filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL ), + 'request_uri' => $this->sanitize_request_uri( filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL ) ), ), ); @@ -431,4 +431,52 @@ class RemoteLogger extends \WC_Log_Handler { protected function is_dev_or_local_environment() { return in_array( wp_get_environment_type(), array( 'development', 'local' ), true ); } + /** + * Sanitize the request URI to only allow certain query parameters. + * + * @param string $request_uri The request URI to sanitize. + * @return string The sanitized request URI. + */ + private function sanitize_request_uri( $request_uri ) { + $default_whitelist = array( 'path', 'page', 'step', 'task', 'tab' ); + + /** + * Filter to allow other plugins to whitelist request_uri query parameter values for unmasked remote logging. + * + * @since 9.4.0 + * + * @param string $default_whitelist The default whitelist of query parameters. + */ + $whitelist = apply_filters( 'woocommerce_remote_logger_request_uri_whitelist', $default_whitelist ); + + $parsed_url = wp_parse_url( $request_uri ); + if ( ! isset( $parsed_url['query'] ) ) { + return $request_uri; + } + + parse_str( $parsed_url['query'], $query_params ); + + foreach ( $query_params as $key => &$value ) { + if ( ! in_array( $key, $whitelist, true ) ) { + $value = 'xxxxxx'; + } + } + + $parsed_url['query'] = http_build_query( $query_params ); + return $this->build_url( $parsed_url ); + } + + /** + * Build a URL from its parsed components. + * + * @param array $parsed_url The parsed URL components. + * @return string The built URL. + */ + private function build_url( $parsed_url ) { + $path = $parsed_url['path'] ?? ''; + $query = isset( $parsed_url['query'] ) ? "?{$parsed_url['query']}" : ''; + $fragment = isset( $parsed_url['fragment'] ) ? "#{$parsed_url['fragment']}" : ''; + + return "$path$query$fragment"; + } } diff --git a/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php b/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php index 63327438a03..1133880bad2 100644 --- a/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php +++ b/plugins/woocommerce/tests/php/src/Internal/Logging/RemoteLoggerTest.php @@ -1,547 +1,646 @@ sut = wc_get_container()->get( RemoteLogger::class ); - } + class RemoteLoggerTest extends \WC_Unit_Test_Case { + /** + * System under test. + * + * @var RemoteLogger + */ + private $sut; - /** - * Tear down. - * - * @return void - */ - public function tearDown(): void { - $this->cleanup_filters(); - delete_option( 'woocommerce_feature_remote_logging_enabled' ); - delete_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); - global $wpdb; - $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_rate_limits" ); - WC_Cache_Helper::invalidate_cache_group( WC_Rate_Limiter::CACHE_GROUP ); - } - - /** - * Cleanup filters used in tests. - * - * @return void - */ - private function cleanup_filters() { - $filters = array( - 'option_woocommerce_admin_remote_feature_enabled', - 'option_woocommerce_allow_tracking', - 'option_woocommerce_version', - 'option_woocommerce_remote_variant_assignment', - 'plugins_api', - 'pre_http_request', - 'woocommerce_remote_logger_formatted_log_data', - 'pre_site_transient_update_plugins', - ); - foreach ( $filters as $filter ) { - remove_all_filters( $filter ); + /** + * Set up test + * + * @return void + */ + public function setUp(): void { + parent::setUp(); + $this->sut = wc_get_container()->get( RemoteLogger::class ); } - } - /** - * @testdox Remote logging is allowed when all conditions are met - */ - public function test_remote_logging_allowed() { - $this->setup_remote_logging_conditions( true ); - $this->assertTrue( $this->sut->is_remote_logging_allowed() ); - } + /** + * Tear down. + * + * @return void + */ + public function tearDown(): void { + $this->cleanup_filters(); + delete_option( 'woocommerce_feature_remote_logging_enabled' ); + delete_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); + global $wpdb; + $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_rate_limits" ); + WC_Cache_Helper::invalidate_cache_group( WC_Rate_Limiter::CACHE_GROUP ); + } - /** - * @testdox Remote logging is not allowed under various conditions - * @dataProvider remote_logging_disallowed_provider - * - * @param string $condition The condition being tested. - * @param callable $setup_callback Callback to set up the test condition. - */ - public function test_remote_logging_not_allowed( $condition, $setup_callback ) { - $this->setup_remote_logging_conditions( true ); - $setup_callback( $this ); - $this->assertFalse( $this->sut->is_remote_logging_allowed() ); - } + /** + * Cleanup filters used in tests. + * + * @return void + */ + private function cleanup_filters() { + $filters = array( + 'option_woocommerce_admin_remote_feature_enabled', + 'option_woocommerce_allow_tracking', + 'option_woocommerce_version', + 'option_woocommerce_remote_variant_assignment', + 'plugins_api', + 'pre_http_request', + 'woocommerce_remote_logger_formatted_log_data', + 'pre_site_transient_update_plugins', + 'woocommerce_remote_logger_request_uri_whitelist', + ); + foreach ( $filters as $filter ) { + remove_all_filters( $filter ); + } + } - /** - * Data provider for test_remote_logging_not_allowed. - * - * @return array[] Test cases with conditions and setup callbacks. - */ - public function remote_logging_disallowed_provider() { - return array( - 'feature flag disabled' => array( - 'condition' => 'feature flag disabled', - 'setup' => fn() => update_option( 'woocommerce_feature_remote_logging_enabled', 'no' ), - ), - 'tracking opted out' => array( - 'condition' => 'tracking opted out', - 'setup' => fn() => add_filter( 'option_woocommerce_allow_tracking', fn() => 'no' ), - ), - 'high variant assignment' => array( - 'condition' => 'high variant assignment', - 'setup' => fn() => add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 15 ), - ), - 'outdated version' => array( - 'condition' => 'outdated version', - 'setup' => function () { - $version = WC()->version; - // Next major version. (e.g. 9.0.1 -> 10.0.0). - $next_version = implode( - '.', - array_map( - function ( $n, $i ) { - return 0 === $i ? $n + 1 : 0; - }, - explode( '.', $version ), - array_keys( explode( '.', $version ) ) - ) - ); + /** + * @testdox Remote logging is allowed when all conditions are met + */ + public function test_remote_logging_allowed() { + $this->setup_remote_logging_conditions( true ); + $this->assertTrue( $this->sut->is_remote_logging_allowed() ); + } - set_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT, $next_version, WEEK_IN_SECONDS ); - }, - ), - ); - } + /** + * @testdox Remote logging is not allowed under various conditions + * @dataProvider remote_logging_disallowed_provider + * + * @param string $condition The condition being tested. + * @param callable $setup_callback Callback to set up the test condition. + */ + public function test_remote_logging_not_allowed( $condition, $setup_callback ) { + $this->setup_remote_logging_conditions( true ); + $setup_callback( $this ); + $this->assertFalse( $this->sut->is_remote_logging_allowed() ); + } + /** + * Data provider for test_remote_logging_not_allowed. + * + * @return array[] Test cases with conditions and setup callbacks. + */ + public function remote_logging_disallowed_provider() { + return array( + 'feature flag disabled' => array( + 'condition' => 'feature flag disabled', + 'setup' => fn() => update_option( 'woocommerce_feature_remote_logging_enabled', 'no' ), + ), + 'tracking opted out' => array( + 'condition' => 'tracking opted out', + 'setup' => fn() => add_filter( 'option_woocommerce_allow_tracking', fn() => 'no' ), + ), + 'high variant assignment' => array( + 'condition' => 'high variant assignment', + 'setup' => fn() => add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 15 ), + ), + 'outdated version' => array( + 'condition' => 'outdated version', + 'setup' => function () { + $version = WC()->version; + // Next major version. (e.g. 9.0.1 -> 10.0.0). + $next_version = implode( + '.', + array_map( + function ( $n, $i ) { + return 0 === $i ? $n + 1 : 0; + }, + explode( '.', $version ), + array_keys( explode( '.', $version ) ) + ) + ); - /** - * @testdox should_current_version_be_logged method behaves correctly - * @dataProvider should_current_version_be_logged_provider - * - * @param string $current_version The current WooCommerce version. - * @param string $new_version The new WooCommerce version. - * @param string $transient_value The value of the transient. - * @param bool $expected The expected result. - */ - public function test_should_current_version_be_logged( $current_version, $new_version, $transient_value, $expected ) { - $wc_version = WC()->version; - WC()->version = $current_version; + set_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT, $next_version, WEEK_IN_SECONDS ); + }, + ), + ); + } - // Set up the transient. - if ( null !== $transient_value ) { - set_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT, $transient_value, WEEK_IN_SECONDS ); - } else { + /** + * @testdox should_current_version_be_logged method behaves correctly + * @dataProvider should_current_version_be_logged_provider + * + * @param string $current_version The current WooCommerce version. + * @param string $new_version The new WooCommerce version. + * @param string $transient_value The value of the transient. + * @param bool $expected The expected result. + */ + public function test_should_current_version_be_logged( $current_version, $new_version, $transient_value, $expected ) { + $wc_version = WC()->version; + WC()->version = $current_version; + + // Set up the transient. + if ( null !== $transient_value ) { + set_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT, $transient_value, WEEK_IN_SECONDS ); + } else { + delete_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); + + $this->setup_mock_plugin_updates( $new_version ); + } + + $result = $this->invoke_private_method( $this->sut, 'should_current_version_be_logged', array() ); + $this->assertEquals( $expected, $result ); + + // Clean up. delete_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); - $this->setup_mock_plugin_updates( $new_version ); + WC()->version = $wc_version; } - $result = $this->invoke_private_method( $this->sut, 'should_current_version_be_logged', array() ); - $this->assertEquals( $expected, $result ); - - // Clean up. - delete_site_transient( RemoteLogger::WC_NEW_VERSION_TRANSIENT ); - - WC()->version = $wc_version; - } - - /** - * Data provider for test_should_current_version_be_logged. - */ - public function should_current_version_be_logged_provider() { - return array( - 'current version is latest (transient set)' => array( '9.2.0', '9.2.0', '9.2.0', true ), - 'current version is newer (transient set)' => array( '9.3.0', '9.2.0', '9.2.0', true ), - 'current version is older (transient set)' => array( '9.1.0', '9.2.0', '9.2.0', false ), - 'new version is null (transient set)' => array( '9.2.0', null, null, true ), - 'transient not set, current version is latest' => array( '9.2.0', '9.2.0', null, true ), - 'transient not set, current version is newer' => array( '9.3.0', '9.2.0', null, true ), - 'transient not set, current version is older' => array( '9.1.0', '9.2.0', null, false ), - 'transient not set, new version is null' => array( '9.2.0', null, null, true ), - ); - } - - /** - * @testdox fetch_new_woocommerce_version method returns correct version - */ - public function test_fetch_new_woocommerce_version() { - $this->setup_mock_plugin_updates( '9.3.0' ); - - $result = $this->invoke_private_method( $this->sut, 'fetch_new_woocommerce_version', array() ); - $this->assertEquals( '9.3.0', $result, 'The result should be the latest version when an update is available.' ); - } - - /** - * @testdox fetch_new_woocommerce_version method returns null when no update is available - */ - public function test_fetch_new_woocommerce_version_no_update() { - add_filter( 'pre_site_transient_update_plugins', fn() => array() ); - - $result = $this->invoke_private_method( $this->sut, 'fetch_new_woocommerce_version', array() ); - $this->assertNull( $result, 'The result should be null when no update is available.' ); - } - - /** - * @testdox get_formatted_log method returns expected array structure - * @dataProvider get_formatted_log_provider - * - * @param string $level The log level. - * @param string $message The log message. - * @param array $context The log context. - * @param array $expected The expected formatted log array. - */ - public function test_get_formatted_log( $level, $message, $context, $expected ) { - $formatted_log = $this->sut->get_formatted_log( $level, $message, $context ); - foreach ( $expected as $key => $value ) { - $this->assertArrayHasKey( $key, $formatted_log ); - $this->assertEquals( $value, $formatted_log[ $key ] ); + /** + * Data provider for test_should_current_version_be_logged. + */ + public function should_current_version_be_logged_provider() { + return array( + 'current version is latest (transient set)' => array( '9.2.0', '9.2.0', '9.2.0', true ), + 'current version is newer (transient set)' => array( '9.3.0', '9.2.0', '9.2.0', true ), + 'current version is older (transient set)' => array( '9.1.0', '9.2.0', '9.2.0', false ), + 'new version is null (transient set)' => array( '9.2.0', null, null, true ), + 'transient not set, current version is latest' => array( '9.2.0', '9.2.0', null, true ), + 'transient not set, current version is newer' => array( '9.3.0', '9.2.0', null, true ), + 'transient not set, current version is older' => array( '9.1.0', '9.2.0', null, false ), + 'transient not set, new version is null' => array( '9.2.0', null, null, true ), + ); } - } - /** - * Data provider for test_get_formatted_log. - * - * @return array[] Test cases with log data and expected formatted output. - */ - public function get_formatted_log_provider() { - return array( - 'basic log data' => array( - 'error', - 'Fatal error occurred at line 123 in ' . ABSPATH . 'wp-content/file.php', - array( 'tags' => array( 'tag1', 'tag2' ) ), - array( - 'feature' => 'woocommerce_core', - 'severity' => 'error', - 'message' => 'Fatal error occurred at line 123 in **/wp-content/file.php', - 'tags' => array( 'woocommerce', 'php', 'tag1', 'tag2' ), - ), - ), - 'log with backtrace' => array( - 'error', - 'Test error message', - array( 'backtrace' => ABSPATH . 'wp-content/plugins/woocommerce/file.php' ), - array( 'trace' => '**/woocommerce/file.php' ), - ), - 'log with extra attributes' => array( - 'error', - 'Test error message', - array( - 'extra' => array( - 'key1' => 'value1', - 'key2' => 'value2', + /** + * @testdox fetch_new_woocommerce_version method returns correct version + */ + public function test_fetch_new_woocommerce_version() { + $this->setup_mock_plugin_updates( '9.3.0' ); + + $result = $this->invoke_private_method( $this->sut, 'fetch_new_woocommerce_version', array() ); + $this->assertEquals( '9.3.0', $result, 'The result should be the latest version when an update is available.' ); + } + + /** + * @testdox fetch_new_woocommerce_version method returns null when no update is available + */ + public function test_fetch_new_woocommerce_version_no_update() { + add_filter( 'pre_site_transient_update_plugins', fn() => array() ); + + $result = $this->invoke_private_method( $this->sut, 'fetch_new_woocommerce_version', array() ); + $this->assertNull( $result, 'The result should be null when no update is available.' ); + } + + + /** + * @testdox get_formatted_log method returns expected array structure + * @dataProvider get_formatted_log_provider + * + * @param string $level The log level. + * @param string $message The log message. + * @param array $context The log context. + * @param array $expected The expected formatted log array. + */ + public function test_get_formatted_log( $level, $message, $context, $expected ) { + $formatted_log = $this->sut->get_formatted_log( $level, $message, $context ); + foreach ( $expected as $key => $value ) { + $this->assertArrayHasKey( $key, $formatted_log ); + $this->assertEquals( $value, $formatted_log[ $key ] ); + } + } + + /** + * Data provider for test_get_formatted_log. + * + * @return array[] Test cases with log data and expected formatted output. + */ + public function get_formatted_log_provider() { + return array( + 'basic log data' => array( + 'error', + 'Fatal error occurred at line 123 in ' . ABSPATH . 'wp-content/file.php', + array( 'tags' => array( 'tag1', 'tag2' ) ), + array( + 'feature' => 'woocommerce_core', + 'severity' => 'error', + 'message' => 'Fatal error occurred at line 123 in **/wp-content/file.php', + 'tags' => array( 'woocommerce', 'php', 'tag1', 'tag2' ), ), ), - array( - 'extra' => array( - 'key1' => 'value1', - 'key2' => 'value2', + 'log with backtrace' => array( + 'error', + 'Test error message', + array( 'backtrace' => ABSPATH . 'wp-content/plugins/woocommerce/file.php' ), + array( 'trace' => '**/woocommerce/file.php' ), + ), + 'log with extra attributes' => array( + 'error', + 'Test error message', + array( + 'extra' => array( + 'key1' => 'value1', + 'key2' => 'value2', + ), + ), + array( + 'extra' => array( + 'key1' => 'value1', + 'key2' => 'value2', + ), ), ), - ), - ); - } + ); + } - /** - * @testdox should_handle method behaves correctly under different conditions - * @dataProvider should_handle_provider - * - * @param callable $setup Function to set up the test environment. - * @param string $level Log level to test. - * @param bool $expected Expected result of should_handle method. - */ - public function test_should_handle( $setup, $level, $expected ) { - $this->sut = $this->getMockBuilder( RemoteLogger::class ) + + /** + * @testdox get_formatted_log method correctly sanitizes request URI + */ + public function test_get_formatted_log_sanitizes_request_uri() { + global $mock_filter_input, $mock_return; + $mock_filter_input = true; + $mock_return = '/shop?path=home&user=admin&token=abc123'; + + $formatted_log = $this->sut->get_formatted_log( 'error', 'Test message', array() ); + + $mock_filter_input = false; + + $this->assertArrayHasKey( 'properties', $formatted_log ); + $this->assertArrayHasKey( 'request_uri', $formatted_log['properties'] ); + $this->assertNotNull( $formatted_log['properties']['request_uri'], 'Request URI should not be null' ); + $this->assertStringContainsString( 'path=home', $formatted_log['properties']['request_uri'] ); + $this->assertStringContainsString( 'user=xxxxxx', $formatted_log['properties']['request_uri'] ); + $this->assertStringContainsString( 'token=xxxxxx', $formatted_log['properties']['request_uri'] ); + } + + /** + * @testdox sanitize_request_uri method respects whitelist filter + */ + public function test_sanitize_request_uri_respects_whitelist_filter() { + add_filter( + 'woocommerce_remote_logger_request_uri_whitelist', + function ( $whitelist ) { + $whitelist[] = 'custom_param'; + return $whitelist; + } + ); + + $request_uri = '/shop?path=home&custom_param=value&token=abc123'; + $sanitized_uri = $this->invoke_private_method( $this->sut, 'sanitize_request_uri', array( $request_uri ) ); + $this->assertStringContainsString( 'path=home', $sanitized_uri ); + $this->assertStringContainsString( 'custom_param=value', $sanitized_uri ); + $this->assertStringContainsString( 'token=xxxxxx', $sanitized_uri ); + } + + /** + * @testdox sanitize_request_uri method correctly sanitizes request URIs + */ + public function test_sanitize_request_uri() { + $reflection = new \ReflectionClass( $this->sut ); + $method = $reflection->getMethod( 'sanitize_request_uri' ); + $method->setAccessible( true ); + + // Test with whitelisted parameters. + $request_uri = '/shop?path=home&page=2&step=1&task=checkout'; + $sanitized_uri = $method->invokeArgs( $this->sut, array( $request_uri ) ); + $this->assertStringContainsString( 'path=home', $sanitized_uri ); + $this->assertStringContainsString( 'page=2', $sanitized_uri ); + $this->assertStringContainsString( 'step=1', $sanitized_uri ); + $this->assertStringContainsString( 'task=checkout', $sanitized_uri ); + + // Test with non-whitelisted parameters. + $request_uri = '/shop?path=home&user=admin&token=abc123'; + $sanitized_uri = $method->invokeArgs( $this->sut, array( $request_uri ) ); + $this->assertStringContainsString( 'path=home', $sanitized_uri ); + $this->assertStringContainsString( 'user=xxxxxx', $sanitized_uri ); + $this->assertStringContainsString( 'token=xxxxxx', $sanitized_uri ); + + // Test with mixed parameters. + $request_uri = '/shop?path=home&page=2&user=admin&step=1&token=abc123'; + $sanitized_uri = $method->invokeArgs( $this->sut, array( $request_uri ) ); + $this->assertStringContainsString( 'path=home', $sanitized_uri ); + $this->assertStringContainsString( 'page=2', $sanitized_uri ); + $this->assertStringContainsString( 'step=1', $sanitized_uri ); + $this->assertStringContainsString( 'user=xxxxxx', $sanitized_uri ); + $this->assertStringContainsString( 'token=xxxxxx', $sanitized_uri ); + } + + /** + * @testdox should_handle method behaves correctly under different conditions + * @dataProvider should_handle_provider + * + * @param callable $setup Function to set up the test environment. + * @param string $level Log level to test. + * @param bool $expected Expected result of should_handle method. + */ + public function test_should_handle( $setup, $level, $expected ) { + $this->sut = $this->getMockBuilder( RemoteLogger::class ) ->onlyMethods( array( 'is_remote_logging_allowed', 'is_third_party_error' ) ) ->getMock(); - $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); - $this->sut->method( 'is_third_party_error' )->willReturn( false ); + $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); + $this->sut->method( 'is_third_party_error' )->willReturn( false ); - $setup( $this ); + $setup( $this ); - $result = $this->invoke_private_method( $this->sut, 'should_handle', array( $level, 'Test message', array() ) ); - $this->assertEquals( $expected, $result ); - } + $result = $this->invoke_private_method( $this->sut, 'should_handle', array( $level, 'Test message', array() ) ); + $this->assertEquals( $expected, $result ); + } - /** - * Data provider for test_should_handle method. - * - * @return array Test cases for should_handle method. - */ - public function should_handle_provider() { - return array( - 'throttled' => array( - fn() => WC_Rate_Limiter::set_rate_limit( RemoteLogger::RATE_LIMIT_ID, 10 ), - 'critical', - false, - ), - 'less severe than critical' => array( - fn() => null, - 'error', - false, - ), - 'critical level' => array( - fn() => null, - 'critical', - true, - ), - ); - } + /** + * Data provider for test_should_handle method. + * + * @return array Test cases for should_handle method. + */ + public function should_handle_provider() { + return array( + 'throttled' => array( + fn() => WC_Rate_Limiter::set_rate_limit( RemoteLogger::RATE_LIMIT_ID, 10 ), + 'critical', + false, + ), + 'less severe than critical' => array( + fn() => null, + 'error', + false, + ), + 'critical level' => array( + fn() => null, + 'critical', + true, + ), + ); + } - /** - * @testdox handle method applies filter and doesn't send logs when filtered to null - */ - public function test_handle_filtered_log_null() { - $this->sut = $this->getMockBuilder( RemoteLogger::class ) + /** + * @testdox handle method applies filter and doesn't send logs when filtered to null + */ + public function test_handle_filtered_log_null() { + $this->sut = $this->getMockBuilder( RemoteLogger::class ) ->onlyMethods( array( 'is_remote_logging_allowed' ) ) ->getMock(); - $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); + $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); - add_filter( 'woocommerce_remote_logger_formatted_log_data', fn() => null, 10, 4 ); - add_filter( 'pre_http_request', fn() => $this->fail( 'wp_safe_remote_post should not be called' ), 10, 3 ); + add_filter( 'woocommerce_remote_logger_formatted_log_data', fn() => null, 10, 4 ); + add_filter( 'pre_http_request', fn() => $this->fail( 'wp_safe_remote_post should not be called' ), 10, 3 ); - $this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) ); - } + $this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) ); + } - /** - * @testdox handle method does not send logs in dev environment - */ - public function test_handle_does_not_send_logs_in_dev_environment() { - $this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class ) + /** + * @testdox handle method does not send logs in dev environment + */ + public function test_handle_does_not_send_logs_in_dev_environment() { + $this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class ) ->onlyMethods( array( 'is_remote_logging_allowed' ) ) ->getMock(); - $this->sut->set_is_dev_or_local( true ); - $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); + $this->sut->set_is_dev_or_local( true ); + $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); - $this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) ); - } + $this->assertFalse( $this->sut->handle( time(), 'error', 'Test message', array() ) ); + } - /** - * @testdox handle method successfully sends log - */ - public function test_handle_successful() { - $this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class ) + /** + * @testdox handle method successfully sends log + */ + public function test_handle_successful() { + $this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class ) ->onlyMethods( array( 'is_remote_logging_allowed' ) ) ->getMock(); - $this->sut->set_is_dev_or_local( false ); - $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); + $this->sut->set_is_dev_or_local( false ); + $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); - add_filter( - 'pre_http_request', - function ( $preempt, $args ) { - $this->assertArrayHasKey( 'body', $args ); - $this->assertArrayHasKey( 'headers', $args ); - return array( - 'response' => array( - 'code' => 200, - 'message' => 'OK', + add_filter( + 'pre_http_request', + function ( $preempt, $args ) { + $this->assertArrayHasKey( 'body', $args ); + $this->assertArrayHasKey( 'headers', $args ); + return array( + 'response' => array( + 'code' => 200, + 'message' => 'OK', + ), + 'body' => wp_json_encode( array( 'success' => true ) ), + ); + }, + 10, + 3 + ); + + $this->assertTrue( $this->sut->handle( time(), 'critical', 'Test message', array() ) ); + $this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) ); + } + + /** + * @testdox handle method handles remote logging failure + */ + public function test_handle_remote_logging_failure() { + $this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class ) + ->onlyMethods( array( 'is_remote_logging_allowed' ) ) + ->getMock(); + + $this->sut->set_is_dev_or_local( false ); + $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); + + add_filter( + 'pre_http_request', + function ( $preempt, $args, $url ) { + if ( 'https://public-api.wordpress.com/rest/v1.1/logstash' === $url ) { + throw new \Exception( 'Remote logging failed: A valid URL was not provided.' ); + } + return $preempt; + }, + 10, + 3 + ); + + $this->assertFalse( $this->sut->handle( time(), 'critical', 'Test message', array() ) ); + $this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) ); + } + + /** + * @testdox is_third_party_error method correctly identifies third-party errors + * @dataProvider is_third_party_error_provider + * @param string $message The error message to check. + * @param array $context The context of the error. + * @param bool $expected_result The expected result of the check. + */ + public function test_is_third_party_error( $message, $context, $expected_result ) { + $result = $this->invoke_private_method( $this->sut, 'is_third_party_error', array( $message, $context ) ); + $this->assertEquals( $expected_result, $result ); + } + + /** + * Data provider for test_is_third_party_error. + * + * @return array[] Test cases. + */ + public function is_third_party_error_provider() { + return array( + array( 'Fatal error in ' . WC_ABSPATH . 'file.php', array(), false ), + array( 'Fatal error in /wp-content/file.php', array(), false ), + array( 'Fatal error in /wp-content/file.php', array( 'source' => 'fatal-errors' ), false ), + array( + 'Fatal error in /wp-content/plugins/3rd-plugin/file.php', + array( + 'source' => 'fatal-errors', + 'backtrace' => array( '/wp-content/plugins/3rd-plugin/file.php', WC_ABSPATH . 'file.php' ), ), - 'body' => wp_json_encode( array( 'success' => true ) ), - ); - }, - 10, - 3 - ); - - $this->assertTrue( $this->sut->handle( time(), 'critical', 'Test message', array() ) ); - $this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) ); - } - - /** - * @testdox handle method handles remote logging failure - */ - public function test_handle_remote_logging_failure() { - $this->sut = $this->getMockBuilder( RemoteLoggerWithEnvironmentOverride::class ) - ->onlyMethods( array( 'is_remote_logging_allowed' ) ) - ->getMock(); - - $this->sut->set_is_dev_or_local( false ); - $this->sut->method( 'is_remote_logging_allowed' )->willReturn( true ); - - add_filter( - 'pre_http_request', - function ( $preempt, $args, $url ) { - if ( 'https://public-api.wordpress.com/rest/v1.1/logstash' === $url ) { - throw new \Exception( 'Remote logging failed: A valid URL was not provided.' ); - } - return $preempt; - }, - 10, - 3 - ); - - $this->assertFalse( $this->sut->handle( time(), 'critical', 'Test message', array() ) ); - $this->assertTrue( WC_Rate_Limiter::retried_too_soon( RemoteLogger::RATE_LIMIT_ID ) ); - } - - /** - * @testdox is_third_party_error method correctly identifies third-party errors - * @dataProvider is_third_party_error_provider - * @param string $message The error message to check. - * @param array $context The context of the error. - * @param bool $expected_result The expected result of the check. - */ - public function test_is_third_party_error( $message, $context, $expected_result ) { - $result = $this->invoke_private_method( $this->sut, 'is_third_party_error', array( $message, $context ) ); - $this->assertEquals( $expected_result, $result ); - } - - /** - * Data provider for test_is_third_party_error. - * - * @return array[] Test cases. - */ - public function is_third_party_error_provider() { - return array( - array( 'Fatal error in ' . WC_ABSPATH . 'file.php', array(), false ), - array( 'Fatal error in /wp-content/file.php', array(), false ), - array( 'Fatal error in /wp-content/file.php', array( 'source' => 'fatal-errors' ), false ), - array( - 'Fatal error in /wp-content/plugins/3rd-plugin/file.php', + false, + ), array( - 'source' => 'fatal-errors', - 'backtrace' => array( '/wp-content/plugins/3rd-plugin/file.php', WC_ABSPATH . 'file.php' ), + 'Fatal error in /wp-content/plugins/woocommerce-3rd-plugin/file.php', + array( + 'source' => 'fatal-errors', + 'backtrace' => array( WP_PLUGIN_DIR . 'woocommerce-3rd-plugin/file.php' ), + ), + true, ), - false, - ), - array( - 'Fatal error in /wp-content/plugins/woocommerce-3rd-plugin/file.php', array( - 'source' => 'fatal-errors', - 'backtrace' => array( WP_PLUGIN_DIR . 'woocommerce-3rd-plugin/file.php' ), + 'Fatal error in /wp-content/plugins/3rd-plugin/file.php', + array( + 'source' => 'fatal-errors', + 'backtrace' => array( WP_PLUGIN_DIR . '3rd-plugin/file.php' ), + ), + true, ), - true, - ), - array( - 'Fatal error in /wp-content/plugins/3rd-plugin/file.php', array( - 'source' => 'fatal-errors', - 'backtrace' => array( WP_PLUGIN_DIR . '3rd-plugin/file.php' ), + 'Fatal error in /wp-content/plugins/3rd-plugin/file.php', + array( + 'source' => 'fatal-errors', + 'backtrace' => array( array( 'file' => WP_PLUGIN_DIR . '3rd-plugin/file.php' ) ), + ), + true, ), - true, - ), - array( - 'Fatal error in /wp-content/plugins/3rd-plugin/file.php', - array( - 'source' => 'fatal-errors', - 'backtrace' => array( array( 'file' => WP_PLUGIN_DIR . '3rd-plugin/file.php' ) ), + ); + } + + /** + * @testdox sanitize method correctly sanitizes paths + */ + public function test_sanitize() { + $message = WC_ABSPATH . 'includes/class-wc-test.php on line 123'; + $expected = '**/woocommerce/includes/class-wc-test.php on line 123'; + $result = $this->invoke_private_method( $this->sut, 'sanitize', array( $message ) ); + $this->assertEquals( $expected, $result ); + } + + /** + * @testdox sanitize_trace method correctly sanitizes stack traces + */ + public function test_sanitize_trace() { + $trace = array( + WC_ABSPATH . 'includes/class-wc-test.php:123', + ABSPATH . 'wp-includes/plugin.php:456', + ); + $expected = "**/woocommerce/includes/class-wc-test.php:123\n**/wp-includes/plugin.php:456"; + $result = $this->invoke_private_method( $this->sut, 'sanitize_trace', array( $trace ) ); + $this->assertEquals( $expected, $result ); + } + + /** + * Setup common conditions for remote logging tests. + * + * @param bool $enabled Whether remote logging is enabled. + */ + private function setup_remote_logging_conditions( $enabled = true ) { + update_option( 'woocommerce_feature_remote_logging_enabled', $enabled ? 'yes' : 'no' ); + add_filter( 'option_woocommerce_allow_tracking', fn() => 'yes' ); + add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 5 ); + $this->setup_mock_plugin_updates( $enabled ? WC()->version : '9.0.0' ); + } + + /** + * Set up mock plugin updates. + * + * @param string $new_version The new version of WooCommerce to simulate. + */ + private function setup_mock_plugin_updates( $new_version ) { + $update_plugins = (object) array( + 'response' => array( + WC_PLUGIN_BASENAME => (object) array( + 'new_version' => $new_version, + 'package' => 'https://downloads.wordpress.org/plugin/woocommerce.zip', + 'slug' => 'woocommerce', + ), ), - true, - ), - ); - } + ); + add_filter( 'pre_site_transient_update_plugins', fn() => $update_plugins ); + } - /** - * @testdox sanitize method correctly sanitizes paths - */ - public function test_sanitize() { - $message = WC_ABSPATH . 'includes/class-wc-test.php on line 123'; - $expected = '**/woocommerce/includes/class-wc-test.php on line 123'; - $result = $this->invoke_private_method( $this->sut, 'sanitize', array( $message ) ); - $this->assertEquals( $expected, $result ); + /** + * Helper method to invoke private methods. + * + * @param object $obj Object instance. + * @param string $method_name Name of the private method. + * @param array $parameters Parameters to pass to the method. + * @return mixed + */ + private function invoke_private_method( $obj, $method_name, $parameters = array() ) { + $reflection = new \ReflectionClass( get_class( $obj ) ); + $method = $reflection->getMethod( $method_name ); + $method->setAccessible( true ); + return $method->invokeArgs( $obj, $parameters ); + } } - /** - * @testdox sanitize_trace method correctly sanitizes stack traces - */ - public function test_sanitize_trace() { - $trace = array( - WC_ABSPATH . 'includes/class-wc-test.php:123', - ABSPATH . 'wp-includes/plugin.php:456', - ); - $expected = "**/woocommerce/includes/class-wc-test.php:123\n**/wp-includes/plugin.php:456"; - $result = $this->invoke_private_method( $this->sut, 'sanitize_trace', array( $trace ) ); - $this->assertEquals( $expected, $result ); - } - - /** - * Setup common conditions for remote logging tests. - * - * @param bool $enabled Whether remote logging is enabled. - */ - private function setup_remote_logging_conditions( $enabled = true ) { - update_option( 'woocommerce_feature_remote_logging_enabled', $enabled ? 'yes' : 'no' ); - add_filter( 'option_woocommerce_allow_tracking', fn() => 'yes' ); - add_filter( 'option_woocommerce_remote_variant_assignment', fn() => 5 ); - $this->setup_mock_plugin_updates( $enabled ? WC()->version : '9.0.0' ); - } - - - /** - * Set up mock plugin updates. - * - * @param string $new_version The new version of WooCommerce to simulate. - */ - private function setup_mock_plugin_updates( $new_version ) { - $update_plugins = (object) array( - 'response' => array( - WC_PLUGIN_BASENAME => (object) array( - 'new_version' => $new_version, - 'package' => 'https://downloads.wordpress.org/plugin/woocommerce.zip', - 'slug' => 'woocommerce', - ), - ), - ); - add_filter( 'pre_site_transient_update_plugins', fn() => $update_plugins ); - } - - /** - * Helper method to invoke private methods. - * - * @param object $obj Object instance. - * @param string $method_name Name of the private method. - * @param array $parameters Parameters to pass to the method. - * @return mixed - */ - private function invoke_private_method( $obj, $method_name, $parameters = array() ) { - $reflection = new \ReflectionClass( get_class( $obj ) ); - $method = $reflection->getMethod( $method_name ); - $method->setAccessible( true ); - return $method->invokeArgs( $obj, $parameters ); - } -} - //phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound, Squiz.Classes.ClassFileName.NoMatch, Suin.Classes.PSR4.IncorrectClassName -/** - * Mock class that extends RemoteLogger to allow overriding is_dev_or_local_environment. - */ -class RemoteLoggerWithEnvironmentOverride extends RemoteLogger { /** - * The is_dev_or_local value. - * - * @var bool + * Mock class that extends RemoteLogger to allow overriding is_dev_or_local_environment. */ - private $is_dev_or_local = false; + class RemoteLoggerWithEnvironmentOverride extends RemoteLogger { + /** + * The is_dev_or_local value. + * + * @var bool + */ + private $is_dev_or_local = false; - /** - * Set the is_dev_or_local value. - * - * @param bool $value The value to set. - */ - public function set_is_dev_or_local( $value ) { - $this->is_dev_or_local = $value; + /** + * Set the is_dev_or_local value. + * + * @param bool $value The value to set. + */ + public function set_is_dev_or_local( $value ) { + $this->is_dev_or_local = $value; + } + + /** + * @inheritDoc + */ + protected function is_dev_or_local_environment() { + return $this->is_dev_or_local; + } } +//phpcs:enable Generic.Files.OneObjectStructurePerFile.MultipleFound, Squiz.Classes.ClassFileName.NoMatch, Suin.Classes.PSR4.IncorrectClassName +} +/** + * Mocks for global functions used in RemoteLogger.php + */ +namespace Automattic\WooCommerce\Internal\Logging { /** - * @inheritDoc + * The filter_input function will return NULL if we change the $_SERVER variables at runtime, so we + * need to override it in RemoteLogger's namespace when we want it to return a specific value for testing. + * + * @return mixed */ - protected function is_dev_or_local_environment() { - return $this->is_dev_or_local; + function filter_input() { + global $mock_filter_input, $mock_return; + + if ( true === $mock_filter_input ) { + return $mock_return; + } else { + return call_user_func_array( '\filter_input', func_get_args() ); + } } } -//phpcs:enable Generic.Files.OneObjectStructurePerFile.MultipleFound, Squiz.Classes.ClassFileName.NoMatch, Suin.Classes.PSR4.IncorrectClassName From 2433664aa8460590b636ff145600f1a3aa7b64f3 Mon Sep 17 00:00:00 2001 From: Manish Menaria Date: Mon, 2 Sep 2024 12:39:33 +0530 Subject: [PATCH 172/185] Product Collection - Show product picker in Editor when collection requires a product but it doesn't exist (#50164) * Show product picker control in the editor when a product context is required but not provided Enhanced the Product Collection block by introducing the `selectedReference` attribute and implementing a product picker control. This control appears in the editor when a product context is required but not provided in the current template/page/post. 1. **block.json**: Added `selectedReference` attribute of type `object`. 2. **constants.ts**: Included `selectedReference` in the `queryContextIncludes` array. 3. **EditorProductPicker.tsx**: Created a new component for selecting products within the editor. 4. **editor.scss**: Added styles for the new Editor Product Picker component. 5. **index.tsx**: Updated logic to determine the component to render, incorporating the new Editor Product Picker. 6. **types.ts**: Defined types for `selectedReference` and updated `ProductCollectionAttributes` interface. This enhancement allows merchants to manually select a product for collections that require a product context, ensuring the block displays correctly even when the product context is not available in the current template/page/post. - **Product Picker Control**: Utilizes the existing `ProductControl` component for selecting products. This component is displayed in the editor when a collection requires a product context but it doesn't exist in the current template/page/post. * Update label on ProductControl component * Implement dynamic UI state management for product collection block - Introduced `ProductCollectionUIStatesInEditor` enum to define various UI states for the product collection block. - Added `getProductCollectionUIStateInEditor` utility function to determine the appropriate UI state based on context. - Updated `Edit` component to use `getProductCollectionUIStateInEditor` for dynamic state management. - Refactored `ProductCollectionContent` to utilize the new Editor UI state management. * Fix: Product picker isn't showing * Fix: Preview label state isn't showing * Add changefile(s) from automation for the following project(s): woocommerce-blocks * Refactor WooCommerceBlockLocation type - Introduced specific interfaces for WooCommerceBlockLocation, including ProductLocation, ArchiveLocation, CartLocation, OrderLocation, and SiteLocation, to improve type safety and code clarity. - Updated createLocationObject function to return a BaseLocation type. - Refactored useSetPreviewState hook in product-collection utils: - Extracted termId from location.sourceData for cleaner and more readable code. - Replaced direct access of location.sourceData?.termId with termId variable. * Remove fallback to 0 in case there may be a product with id 0 * Use optional chaining to avoid undefined errors * Rename to * Change order of arguments in function * Pass boolean prop instead of making further recognition of the UI state in ProductCollectionContent * Destructure props in component * Rename to * Update names in enum * Rename to and change the structure to single number. * Rename location to * Add a method to choose a product in the product picker in Editor * Add E2E tests * Fix failing e2e tests by changing location to productCollectionLocation * Add changefile(s) from automation for the following project(s): woocommerce-blocks * Don't allow selecting product variations * Minor code refactoring * Fix: Product control isn't showing products **Before** ```tsx const getRenderItemFunc = () => { if ( renderItem ) { return renderItem; } else if ( showVariations ) { return renderItemWithVariations; } return () => null; }; ``` As you can see above, `return () => null;` is returning a function which is causing the issue. This will render nothing in the list. I changed this to `return undefined;`. This way, we will use default render item function. * Translate text in ProductPicker component * Improve E2E test * Use createInterpolateElement to safely render strong HTML tag * Fix E2E tests * Fix E2E tests * Product Collection: Inspector control to change selected product (#50590) * Add Linked Product Control to Product Collection Block Inspector Controls - Introduced a new `LinkedProductControl` component in the Product Collection block's Inspector Controls. - This control allows users to link a specific product to the product collection via a dropdown with a search capability. - Added corresponding styles to `editor.scss`. - Integrated a `useGetProduct` hook in the `utils.tsx` to fetch and manage the state of the linked product data, including handling loading states and errors. - Updated the Inspector Controls to include the new Linked Product Control component, enhancing the block's customization options for users. * Add E2E tests * Hide product picker when product context is available * Improve logic to hide Linked Product Control * Add changefile(s) from automation for the following project(s): woocommerce-blocks * Remove hasError state from useGetProduct hook * Rename isShowLinkedProductControl to showLinkedProductControl * Convert jsxProductButton to ProductButton component * Refactor jsxPopoverContent to LinkedProductPopoverContent component * Improve UI of Linked Product Control * Address PR feedback * Fix E2E tests --------- Co-authored-by: github-actions * Rename isUsesReferencePreviewMode to isUsingReferencePreviewMode * Change order of conditions in getProductCollectionUIStateInEditor --------- Co-authored-by: github-actions --- .../product-collection/edit/ProductPicker.tsx | 81 +++++ .../product-collection/edit/editor.scss | 46 +++ .../blocks/product-collection/edit/index.tsx | 46 ++- .../edit/inspector-controls/index.tsx | 8 + .../linked-product-control.tsx | 166 +++++++++ .../edit/product-collection-content.tsx | 13 +- .../js/blocks/product-collection/types.ts | 13 + .../js/blocks/product-collection/utils.tsx | 177 ++++++--- .../js/blocks/product-template/edit.tsx | 2 +- .../js/blocks/product-template/utils.tsx | 70 +++- .../product-control/index.tsx | 17 +- .../product-collection.block_theme.spec.ts | 335 +++++++++++++++++- .../product-collection.page.ts | 57 ++- ...-context-linking-a-product-with-collection | 4 + ...-product-with-collection-inspector-control | 4 + 15 files changed, 953 insertions(+), 86 deletions(-) create mode 100644 plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx create mode 100644 plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/inspector-controls/linked-product-control.tsx create mode 100644 plugins/woocommerce/changelog/50164-add-44877-context-linking-a-product-with-collection create mode 100644 plugins/woocommerce/changelog/50590-add-44877-context-linking-a-product-with-collection-inspector-control diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx new file mode 100644 index 00000000000..3d80edf035c --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx @@ -0,0 +1,81 @@ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { useBlockProps } from '@wordpress/block-editor'; +import { Icon, info } from '@wordpress/icons'; +import ProductControl from '@woocommerce/editor-components/product-control'; +import type { SelectedOption } from '@woocommerce/block-hocs'; +import { createInterpolateElement } from '@wordpress/element'; +import { + Placeholder, + // @ts-expect-error Using experimental features + __experimentalHStack as HStack, + // @ts-expect-error Using experimental features + __experimentalText as Text, +} from '@wordpress/components'; + +/** + * Internal dependencies + */ +import type { ProductCollectionEditComponentProps } from '../types'; +import { getCollectionByName } from '../collections'; + +const ProductPicker = ( props: ProductCollectionEditComponentProps ) => { + const blockProps = useBlockProps(); + const attributes = props.attributes; + + const collection = getCollectionByName( attributes.collection ); + if ( ! collection ) { + return; + } + + return ( +
        + + + + + { createInterpolateElement( + sprintf( + /* translators: %s: collection title */ + __( + '%s requires a product to be selected in order to display associated items.', + 'woocommerce' + ), + collection.title + ), + { + strong: , + } + ) } + + + { + const isValidId = ( value[ 0 ]?.id ?? null ) !== null; + if ( isValidId ) { + props.setAttributes( { + query: { + ...attributes.query, + productReference: value[ 0 ].id, + }, + } ); + } + } } + messages={ { + search: __( 'Select a product', 'woocommerce' ), + } } + /> + +
        + ); +}; + +export default ProductPicker; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/editor.scss b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/editor.scss index 63ecbc2f692..4dac0fe0dc5 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/editor.scss +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/editor.scss @@ -168,3 +168,49 @@ $max-button-width: calc(100% / #{$max-button-columns}); color: var(--wp-components-color-accent-inverted, #fff); } } + +// Editor Product Picker +.wc-blocks-product-collection__editor-product-picker { + .wc-blocks-product-collection__info-icon { + fill: var(--wp--preset--color--luminous-vivid-orange, #e26f56); + } +} + +// Linked Product Control +.wc-block-product-collection-linked-product-control { + width: 100%; + text-align: left; + + &__button { + width: 100%; + height: 100%; + padding: 10px; + border: 1px solid $gray-300; + } + + &__image-container { + flex-shrink: 0; + width: 45px; + height: 45px; + + img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + } + } + + &__content { + text-align: left; + } +} + +.wc-block-product-collection-linked-product__popover-content .components-popover__content { + width: 100%; + + .woocommerce-search-list__search { + border: 0; + padding: 0; + } +} diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/index.tsx index de9dcb3c03d..4206a024714 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/index.tsx @@ -4,18 +4,25 @@ import { store as blockEditorStore } from '@wordpress/block-editor'; import { useState } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; +import { useGetLocation } from '@woocommerce/blocks/product-template/utils'; /** * Internal dependencies */ -import type { ProductCollectionEditComponentProps } from '../types'; +import { + ProductCollectionEditComponentProps, + ProductCollectionUIStatesInEditor, +} from '../types'; import ProductCollectionPlaceholder from './product-collection-placeholder'; import ProductCollectionContent from './product-collection-content'; import CollectionSelectionModal from './collection-selection-modal'; import './editor.scss'; +import { getProductCollectionUIStateInEditor } from '../utils'; +import ProductPicker from './ProductPicker'; const Edit = ( props: ProductCollectionEditComponentProps ) => { const { clientId, attributes } = props; + const location = useGetLocation( props.context, props.clientId ); const [ isSelectionModalOpen, setIsSelectionModalOpen ] = useState( false ); const hasInnerBlocks = useSelect( @@ -24,9 +31,37 @@ const Edit = ( props: ProductCollectionEditComponentProps ) => { [ clientId ] ); - const Component = hasInnerBlocks - ? ProductCollectionContent - : ProductCollectionPlaceholder; + const productCollectionUIStateInEditor = + getProductCollectionUIStateInEditor( { + hasInnerBlocks, + location, + attributes: props.attributes, + usesReference: props.usesReference, + } ); + + /** + * Component to render based on the UI state. + */ + let Component, + isUsingReferencePreviewMode = false; + switch ( productCollectionUIStateInEditor ) { + case ProductCollectionUIStatesInEditor.COLLECTION_PICKER: + Component = ProductCollectionPlaceholder; + break; + case ProductCollectionUIStatesInEditor.PRODUCT_REFERENCE_PICKER: + Component = ProductPicker; + break; + case ProductCollectionUIStatesInEditor.VALID: + Component = ProductCollectionContent; + break; + case ProductCollectionUIStatesInEditor.VALID_WITH_PREVIEW: + Component = ProductCollectionContent; + isUsingReferencePreviewMode = true; + break; + default: + // By default showing collection chooser. + Component = ProductCollectionPlaceholder; + } return ( <> @@ -35,6 +70,9 @@ const Edit = ( props: ProductCollectionEditComponentProps ) => { openCollectionSelectionModal={ () => setIsSelectionModalOpen( true ) } + isUsingReferencePreviewMode={ isUsingReferencePreviewMode } + location={ location } + usesReference={ props.usesReference } /> { isSelectionModalOpen && ( ( filter: FilterName ) => { @@ -121,6 +122,13 @@ const ProductCollectionInspectorControls = ( return ( + + { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/inspector-controls/linked-product-control.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/inspector-controls/linked-product-control.tsx new file mode 100644 index 00000000000..35606aff0a9 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/inspector-controls/linked-product-control.tsx @@ -0,0 +1,166 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import ProductControl from '@woocommerce/editor-components/product-control'; +import { SelectedOption } from '@woocommerce/block-hocs'; +import { useState, useMemo } from '@wordpress/element'; +import type { WooCommerceBlockLocation } from '@woocommerce/blocks/product-template/utils'; +import type { ProductResponseItem } from '@woocommerce/types'; +import { decodeEntities } from '@wordpress/html-entities'; +import { + PanelBody, + PanelRow, + Button, + Flex, + FlexItem, + Dropdown, + // @ts-expect-error Using experimental features + // eslint-disable-next-line @wordpress/no-unsafe-wp-apis + __experimentalText as Text, + Spinner, +} from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { useGetProduct } from '../../utils'; +import type { + ProductCollectionQuery, + ProductCollectionSetAttributes, +} from '../../types'; + +const ProductButton: React.FC< { + isOpen: boolean; + onToggle: () => void; + product: ProductResponseItem | null; + isLoading: boolean; +} > = ( { isOpen, onToggle, product, isLoading } ) => { + if ( isLoading && ! product ) { + return ; + } + + return ( + + ); +}; + +const LinkedProductPopoverContent: React.FC< { + query: ProductCollectionQuery; + setAttributes: ProductCollectionSetAttributes; + setIsDropdownOpen: React.Dispatch< React.SetStateAction< boolean > >; +} > = ( { query, setAttributes, setIsDropdownOpen } ) => ( + { + const productId = value[ 0 ]?.id ?? null; + if ( productId !== null ) { + setAttributes( { + query: { + ...query, + productReference: productId, + }, + } ); + setIsDropdownOpen( false ); + } + } } + messages={ { + search: __( 'Select a product', 'woocommerce' ), + } } + /> +); + +const LinkedProductControl = ( { + query, + setAttributes, + location, + usesReference, +}: { + query: ProductCollectionQuery; + setAttributes: ProductCollectionSetAttributes; + location: WooCommerceBlockLocation; + usesReference: string[] | undefined; +} ) => { + const [ isDropdownOpen, setIsDropdownOpen ] = useState< boolean >( false ); + const { product, isLoading } = useGetProduct( query.productReference ); + + const showLinkedProductControl = useMemo( () => { + const isInRequiredLocation = usesReference?.includes( location.type ); + const isProductContextRequired = usesReference?.includes( 'product' ); + const isProductContextSelected = + ( query?.productReference ?? null ) !== null; + + return ( + isProductContextRequired && + ! isInRequiredLocation && + isProductContextSelected + ); + }, [ location.type, query?.productReference, usesReference ] ); + + if ( ! showLinkedProductControl ) return null; + + return ( + + + ( + + ) } + renderContent={ () => ( + + ) } + open={ isDropdownOpen } + onToggle={ () => setIsDropdownOpen( ! isDropdownOpen ) } + /> + + + ); +}; + +export default LinkedProductControl; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx index dadbddb7751..35714946c42 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx @@ -10,7 +10,6 @@ import { useInstanceId } from '@wordpress/compose'; import { useEffect, useRef, useMemo } from '@wordpress/element'; import { Button } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; -import { useGetLocation } from '@woocommerce/blocks/product-template/utils'; import fastDeepEqual from 'fast-deep-equal/es6'; /** @@ -68,19 +67,23 @@ const useQueryId = ( const ProductCollectionContent = ( { preview: { setPreviewState, initialPreviewState } = {}, - usesReference, ...props }: ProductCollectionEditComponentProps ) => { const isInitialAttributesSet = useRef( false ); - const { clientId, attributes, setAttributes } = props; - const location = useGetLocation( props.context, props.clientId ); + const { + clientId, + attributes, + setAttributes, + location, + isUsingReferencePreviewMode, + } = props; useSetPreviewState( { setPreviewState, setAttributes, location, attributes, - usesReference, + isUsingReferencePreviewMode, } ); const blockProps = useBlockProps(); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/types.ts b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/types.ts index 4407c682abe..55a8ee9b460 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/types.ts +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/types.ts @@ -9,6 +9,16 @@ import { type AttributeMetadata } from '@woocommerce/types'; */ import { WooCommerceBlockLocation } from '../product-template/utils'; +export enum ProductCollectionUIStatesInEditor { + COLLECTION_PICKER = 'collection_chooser', + PRODUCT_REFERENCE_PICKER = 'product_context_picker', + VALID_WITH_PREVIEW = 'uses_reference_preview_mode', + VALID = 'valid', + // Future states + // INVALID = 'invalid', + // DELETED_PRODUCT_REFERENCE = 'deleted_product_reference', +} + export interface ProductCollectionAttributes { query: ProductCollectionQuery; queryId: number; @@ -95,6 +105,7 @@ export interface ProductCollectionQuery { woocommerceHandPickedProducts: string[]; priceRange: undefined | PriceRange; filterable: boolean; + productReference?: number; } export type ProductCollectionEditComponentProps = @@ -108,6 +119,8 @@ export type ProductCollectionEditComponentProps = context: { templateSlug: string; }; + isUsingReferencePreviewMode: boolean; + location: WooCommerceBlockLocation; }; export type TProductCollectionOrder = 'asc' | 'desc'; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/utils.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/utils.tsx index bdbd882e88a..0565027bfe1 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-collection/utils.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-collection/utils.tsx @@ -6,8 +6,10 @@ import { addFilter } from '@wordpress/hooks'; import { select } from '@wordpress/data'; import { isWpVersion } from '@woocommerce/settings'; import type { BlockEditProps, Block } from '@wordpress/blocks'; -import { useLayoutEffect } from '@wordpress/element'; +import { useEffect, useLayoutEffect, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import type { ProductResponseItem } from '@woocommerce/types'; +import { getProduct } from '@woocommerce/editor-components/utils'; import { createBlock, // @ts-expect-error Type definitions for this function are missing in Guteberg @@ -18,13 +20,14 @@ import { * Internal dependencies */ import { - type ProductCollectionAttributes, - type TProductCollectionOrder, - type TProductCollectionOrderBy, - type ProductCollectionQuery, - type ProductCollectionDisplayLayout, - type PreviewState, - type SetPreviewState, + ProductCollectionAttributes, + TProductCollectionOrder, + TProductCollectionOrderBy, + ProductCollectionQuery, + ProductCollectionDisplayLayout, + PreviewState, + SetPreviewState, + ProductCollectionUIStatesInEditor, } from './types'; import { coreQueryPaginationBlockName, @@ -166,41 +169,14 @@ export const addProductCollectionToQueryPaginationParentOrAncestor = () => { }; /** - * Get the preview message for the Product Collection block based on the usesReference. - * There are two scenarios: - * 1. When usesReference is product, the preview message will be: - * "Actual products will vary depending on the product being viewed." - * 2. For all other usesReference, the preview message will be: - * "Actual products will vary depending on the page being viewed." - * - * This message will be shown when the usesReference isn't available on the Editor side, but is available on the Frontend. + * Get the message to show in the preview label when the block is in preview mode based + * on the `usesReference` value. */ export const getUsesReferencePreviewMessage = ( location: WooCommerceBlockLocation, - usesReference?: string[] + isUsingReferencePreviewMode: boolean ) => { - if ( ! ( Array.isArray( usesReference ) && usesReference.length > 0 ) ) { - return ''; - } - - if ( usesReference.includes( location.type ) ) { - /** - * Block shouldn't be in preview mode when: - * 1. Current location is archive and termId is available. - * 2. Current location is product and productId is available. - * - * Because in these cases, we have required context on the editor side. - */ - const isArchiveLocationWithTermId = - location.type === LocationType.Archive && - ( location.sourceData?.termId ?? null ) !== null; - const isProductLocationWithProductId = - location.type === LocationType.Product && - ( location.sourceData?.productId ?? null ) !== null; - if ( isArchiveLocationWithTermId || isProductLocationWithProductId ) { - return ''; - } - + if ( isUsingReferencePreviewMode ) { if ( location.type === LocationType.Product ) { return __( 'Actual products will vary depending on the product being viewed.', @@ -217,12 +193,77 @@ export const getUsesReferencePreviewMessage = ( return ''; }; +export const getProductCollectionUIStateInEditor = ( { + location, + usesReference, + attributes, + hasInnerBlocks, +}: { + location: WooCommerceBlockLocation; + usesReference?: string[] | undefined; + attributes: ProductCollectionAttributes; + hasInnerBlocks: boolean; +} ): ProductCollectionUIStatesInEditor => { + const isInRequiredLocation = usesReference?.includes( location.type ); + const isCollectionSelected = !! attributes.collection; + + /** + * Case 1: Product context picker + */ + const isProductContextRequired = usesReference?.includes( 'product' ); + const isProductContextSelected = + ( attributes.query?.productReference ?? null ) !== null; + if ( + isCollectionSelected && + isProductContextRequired && + ! isInRequiredLocation && + ! isProductContextSelected + ) { + return ProductCollectionUIStatesInEditor.PRODUCT_REFERENCE_PICKER; + } + + /** + * Case 2: Preview mode - based on `usesReference` value + */ + if ( isInRequiredLocation ) { + /** + * Block shouldn't be in preview mode when: + * 1. Current location is archive and termId is available. + * 2. Current location is product and productId is available. + * + * Because in these cases, we have required context on the editor side. + */ + const isArchiveLocationWithTermId = + location.type === LocationType.Archive && + ( location.sourceData?.termId ?? null ) !== null; + const isProductLocationWithProductId = + location.type === LocationType.Product && + ( location.sourceData?.productId ?? null ) !== null; + + if ( + ! isArchiveLocationWithTermId && + ! isProductLocationWithProductId + ) { + return ProductCollectionUIStatesInEditor.VALID_WITH_PREVIEW; + } + } + + /** + * Case 3: Collection chooser + */ + if ( ! hasInnerBlocks && ! isCollectionSelected ) { + return ProductCollectionUIStatesInEditor.COLLECTION_PICKER; + } + + return ProductCollectionUIStatesInEditor.VALID; +}; + export const useSetPreviewState = ( { setPreviewState, location, attributes, setAttributes, - usesReference, + isUsingReferencePreviewMode, }: { setPreviewState?: SetPreviewState | undefined; location: WooCommerceBlockLocation; @@ -231,6 +272,7 @@ export const useSetPreviewState = ( { attributes: Partial< ProductCollectionAttributes > ) => void; usesReference?: string[] | undefined; + isUsingReferencePreviewMode: boolean; } ) => { const setState = ( newPreviewState: PreviewState ) => { setAttributes( { @@ -240,8 +282,6 @@ export const useSetPreviewState = ( { }, } ); }; - const isCollectionUsesReference = - usesReference && usesReference?.length > 0; /** * When usesReference is available on Frontend but not on Editor side, @@ -249,10 +289,10 @@ export const useSetPreviewState = ( { */ const usesReferencePreviewMessage = getUsesReferencePreviewMessage( location, - usesReference + isUsingReferencePreviewMode ); useLayoutEffect( () => { - if ( isCollectionUsesReference ) { + if ( isUsingReferencePreviewMode ) { setAttributes( { __privatePreviewState: { isPreview: usesReferencePreviewMessage.length > 0, @@ -263,12 +303,12 @@ export const useSetPreviewState = ( { }, [ setAttributes, usesReferencePreviewMessage, - isCollectionUsesReference, + isUsingReferencePreviewMode, ] ); // Running setPreviewState function provided by Collection, if it exists. useLayoutEffect( () => { - if ( ! setPreviewState && ! isCollectionUsesReference ) { + if ( ! setPreviewState && ! isUsingReferencePreviewMode ) { return; } @@ -294,11 +334,14 @@ export const useSetPreviewState = ( { * - Products by tag * - Products by attribute */ + const termId = + location.type === LocationType.Archive + ? location.sourceData?.termId + : null; useLayoutEffect( () => { - if ( ! setPreviewState && ! isCollectionUsesReference ) { + if ( ! setPreviewState && ! isUsingReferencePreviewMode ) { const isGenericArchiveTemplate = - location.type === LocationType.Archive && - location.sourceData?.termId === null; + location.type === LocationType.Archive && termId === null; setAttributes( { __privatePreviewState: { @@ -315,11 +358,11 @@ export const useSetPreviewState = ( { }, [ attributes?.query?.inherit, usesReferencePreviewMessage, - location.sourceData?.termId, + termId, location.type, setAttributes, setPreviewState, - isCollectionUsesReference, + isUsingReferencePreviewMode, ] ); }; @@ -356,3 +399,35 @@ export const getDefaultProductCollection = () => }, createBlocksFromInnerBlocksTemplate( INNER_BLOCKS_TEMPLATE ) ); + +export const useGetProduct = ( productId: number | undefined ) => { + const [ product, setProduct ] = useState< ProductResponseItem | null >( + null + ); + const [ isLoading, setIsLoading ] = useState< boolean >( false ); + + useEffect( () => { + const fetchProduct = async () => { + if ( productId ) { + setIsLoading( true ); + try { + const fetchedProduct = ( await getProduct( + productId + ) ) as ProductResponseItem; + setProduct( fetchedProduct ); + } catch ( error ) { + setProduct( null ); + } finally { + setIsLoading( false ); + } + } else { + setProduct( null ); + setIsLoading( false ); + } + }; + + fetchProduct(); + }, [ productId ] ); + + return { product, isLoading }; +}; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-template/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-template/edit.tsx index 5c469725163..1c09035f46e 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-template/edit.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-template/edit.tsx @@ -266,7 +266,7 @@ const ProductTemplateEdit = ( products: getEntityRecords( 'postType', postType, { ...query, ...restQueryArgs, - location, + productCollectionLocation: location, productCollectionQueryContext, previewState: __privateProductCollectionPreviewState, /** diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-template/utils.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-template/utils.tsx index 5f5344a7296..9106d24ba3c 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/product-template/utils.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/product-template/utils.tsx @@ -63,17 +63,65 @@ const prepareIsInGenericTemplate = ( entitySlug: string ): boolean => templateSlug === entitySlug; -export type WooCommerceBlockLocation = ReturnType< - typeof createLocationObject ->; +interface WooCommerceBaseLocation { + type: LocationType; + sourceData?: object | undefined; +} -const createLocationObject = ( - type: LocationType, - sourceData: Record< string, unknown > = {} -) => ( { - type, - sourceData, -} ); +interface ProductLocation extends WooCommerceBaseLocation { + type: LocationType.Product; + sourceData?: + | { + productId: number; + } + | undefined; +} + +interface ArchiveLocation extends WooCommerceBaseLocation { + type: LocationType.Archive; + sourceData?: + | { + taxonomy: string; + termId: number; + } + | undefined; +} + +interface CartLocation extends WooCommerceBaseLocation { + type: LocationType.Cart; + sourceData?: + | { + productIds: number[]; + } + | undefined; +} + +interface OrderLocation extends WooCommerceBaseLocation { + type: LocationType.Order; + sourceData?: + | { + orderId: number; + } + | undefined; +} + +interface SiteLocation extends WooCommerceBaseLocation { + type: LocationType.Site; + sourceData?: object | undefined; +} + +export type WooCommerceBlockLocation = + | ProductLocation + | ArchiveLocation + | CartLocation + | OrderLocation + | SiteLocation; + +const createLocationObject = ( type: LocationType, sourceData: object = {} ) => + ( { + type, + sourceData, + } as WooCommerceBlockLocation ); type ContextProperties = { templateSlug: string; @@ -83,7 +131,7 @@ type ContextProperties = { export const useGetLocation = < T, >( context: Context< T & ContextProperties >, clientId: string -) => { +): WooCommerceBlockLocation => { const templateSlug = context.templateSlug || ''; const postId = context.postId || null; diff --git a/plugins/woocommerce-blocks/assets/js/editor-components/product-control/index.tsx b/plugins/woocommerce-blocks/assets/js/editor-components/product-control/index.tsx index bfa1e5f2a85..f86f2878dc7 100644 --- a/plugins/woocommerce-blocks/assets/js/editor-components/product-control/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/editor-components/product-control/index.tsx @@ -62,6 +62,16 @@ interface ProductControlProps { * Whether to show variations in the list of items available. */ showVariations?: boolean; + /** + * Different messages to display in the component. + * If any of the messages are not provided, the default message will be used. + */ + messages?: { + list?: string; + noItems?: string; + search?: string; + updated?: string; + }; } const messages = { @@ -188,7 +198,7 @@ const ProductControl = ( } else if ( showVariations ) { return renderItemWithVariations; } - return () => null; + return undefined; }; if ( error ) { @@ -216,7 +226,10 @@ const ProductControl = ( onChange={ onChange } renderItem={ getRenderItemFunc() } onSearch={ onSearch } - messages={ messages } + messages={ { + ...messages, + ...props.messages, + } } isHierarchical /> ); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts index af0839c5ca1..e38db1b526a 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.block_theme.spec.ts @@ -9,6 +9,7 @@ import { test as base, expect } from '@woocommerce/e2e-utils'; */ import ProductCollectionPage, { BLOCK_LABELS, + Collections, SELECTORS, } from './product-collection.page'; @@ -402,7 +403,7 @@ test.describe( 'Product Collection', () => { } ); } ); - test.describe( 'Location is recognised', () => { + test.describe( 'Location is recognized', () => { const filterRequest = ( request: Request ) => { const url = request.url(); return ( @@ -418,7 +419,9 @@ test.describe( 'Product Collection', () => { return ( url.includes( 'wp/v2/product' ) && searchParams.get( 'isProductCollectionBlock' ) === 'true' && - !! searchParams.get( `location[sourceData][productId]` ) + !! searchParams.get( + `productCollectionLocation[sourceData][productId]` + ) ); }; @@ -430,26 +433,30 @@ test.describe( 'Product Collection', () => { if ( locationType === 'product' ) { return { - type: searchParams.get( 'location[type]' ), + type: searchParams.get( 'productCollectionLocation[type]' ), productId: searchParams.get( - `location[sourceData][productId]` + `productCollectionLocation[sourceData][productId]` ), }; } if ( locationType === 'archive' ) { return { - type: searchParams.get( 'location[type]' ), + type: searchParams.get( 'productCollectionLocation[type]' ), taxonomy: searchParams.get( - `location[sourceData][taxonomy]` + `productCollectionLocation[sourceData][taxonomy]` + ), + termId: searchParams.get( + `productCollectionLocation[sourceData][termId]` ), - termId: searchParams.get( `location[sourceData][termId]` ), }; } return { - type: searchParams.get( 'location[type]' ), - sourceData: searchParams.get( `location[sourceData]` ), + type: searchParams.get( 'productCollectionLocation[type]' ), + sourceData: searchParams.get( + `productCollectionLocation[sourceData]` + ), }; }; @@ -482,10 +489,10 @@ test.describe( 'Product Collection', () => { pageObject.BLOCK_NAME ); - const locationReuqestPromise = + const locationRequestPromise = page.waitForRequest( filterProductRequest ); await pageObject.chooseCollectionInTemplate( 'featured' ); - const locationRequest = await locationReuqestPromise; + const locationRequest = await locationRequestPromise; const { type, productId } = getLocationDetailsFromRequest( locationRequest, @@ -961,3 +968,309 @@ test.describe( 'Product Collection', () => { } ); } ); } ); + +test.describe( 'Testing "usesReference" argument in "registerProductCollection"', () => { + const MY_REGISTERED_COLLECTIONS = { + myCustomCollectionWithProductContext: { + name: 'My Custom Collection - Product Context', + label: 'Block: My Custom Collection - Product Context', + previewLabelTemplate: [ 'woocommerce/woocommerce//single-product' ], + shouldShowProductPicker: true, + }, + myCustomCollectionWithCartContext: { + name: 'My Custom Collection - Cart Context', + label: 'Block: My Custom Collection - Cart Context', + previewLabelTemplate: [ 'woocommerce/woocommerce//page-cart' ], + shouldShowProductPicker: false, + }, + myCustomCollectionWithOrderContext: { + name: 'My Custom Collection - Order Context', + label: 'Block: My Custom Collection - Order Context', + previewLabelTemplate: [ + 'woocommerce/woocommerce//order-confirmation', + ], + shouldShowProductPicker: false, + }, + myCustomCollectionWithArchiveContext: { + name: 'My Custom Collection - Archive Context', + label: 'Block: My Custom Collection - Archive Context', + previewLabelTemplate: [ + 'woocommerce/woocommerce//taxonomy-product_cat', + ], + shouldShowProductPicker: false, + }, + myCustomCollectionMultipleContexts: { + name: 'My Custom Collection - Multiple Contexts', + label: 'Block: My Custom Collection - Multiple Contexts', + previewLabelTemplate: [ + 'woocommerce/woocommerce//single-product', + 'woocommerce/woocommerce//order-confirmation', + ], + shouldShowProductPicker: true, + }, + }; + + // Activate plugin which registers custom product collections + test.beforeEach( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'register-product-collection-tester' + ); + } ); + + Object.entries( MY_REGISTERED_COLLECTIONS ).forEach( + ( [ key, collection ] ) => { + for ( const template of collection.previewLabelTemplate ) { + test( `Collection "${ collection.name }" should show preview label in "${ template }"`, async ( { + pageObject, + editor, + } ) => { + await pageObject.goToEditorTemplate( template ); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInTemplate( + key as Collections + ); + + const block = editor.canvas.getByLabel( collection.label ); + const previewButtonLocator = block.getByTestId( + SELECTORS.previewButtonTestID + ); + + await expect( previewButtonLocator ).toBeVisible(); + } ); + } + + test( `Collection "${ collection.name }" should not show preview label in a post`, async ( { + pageObject, + editor, + admin, + } ) => { + await admin.createNewPost(); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( key as Collections ); + + // Check visibility of product picker + const editorProductPicker = editor.canvas.locator( + SELECTORS.productPicker + ); + const expectedVisibility = collection.shouldShowProductPicker + ? 'toBeVisible' + : 'toBeHidden'; + await expect( editorProductPicker )[ expectedVisibility ](); + + if ( collection.shouldShowProductPicker ) { + await pageObject.chooseProductInEditorProductPickerIfAvailable( + editor.canvas + ); + } + + // At this point, the product picker should be hidden + await expect( editorProductPicker ).toBeHidden(); + + // Check visibility of preview label + const block = editor.canvas.getByLabel( collection.label ); + const previewButtonLocator = block.getByTestId( + SELECTORS.previewButtonTestID + ); + + await expect( previewButtonLocator ).toBeHidden(); + } ); + + test( `Collection "${ collection.name }" should not show preview label in Product Catalog template`, async ( { + pageObject, + editor, + } ) => { + await pageObject.goToProductCatalogAndInsertCollection( + key as Collections + ); + + const block = editor.canvas.getByLabel( collection.label ); + const previewButtonLocator = block.getByTestId( + SELECTORS.previewButtonTestID + ); + + await expect( previewButtonLocator ).toBeHidden(); + } ); + } + ); +} ); + +test.describe( 'Product picker', () => { + const MY_REGISTERED_COLLECTIONS_THAT_NEEDS_PRODUCT = { + myCustomCollectionWithProductContext: { + name: 'My Custom Collection - Product Context', + label: 'Block: My Custom Collection - Product Context', + collection: + 'woocommerce/product-collection/my-custom-collection-product-context', + }, + myCustomCollectionMultipleContexts: { + name: 'My Custom Collection - Multiple Contexts', + label: 'Block: My Custom Collection - Multiple Contexts', + collection: + 'woocommerce/product-collection/my-custom-collection-multiple-contexts', + }, + }; + + // Activate plugin which registers custom product collections + test.beforeEach( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'register-product-collection-tester' + ); + } ); + + Object.entries( MY_REGISTERED_COLLECTIONS_THAT_NEEDS_PRODUCT ).forEach( + ( [ key, collection ] ) => { + test( `For collection "${ collection.name }" - manually selected product reference should be available on Frontend in a post`, async ( { + pageObject, + admin, + page, + editor, + } ) => { + await admin.createNewPost(); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( key as Collections ); + + // Verify that product picker is shown in Editor + const editorProductPicker = editor.canvas.locator( + SELECTORS.productPicker + ); + await expect( editorProductPicker ).toBeVisible(); + + // Once a product is selected, the product picker should be hidden + await pageObject.chooseProductInEditorProductPickerIfAvailable( + editor.canvas + ); + await expect( editorProductPicker ).toBeHidden(); + + // On Frontend, verify that product reference is a number + await pageObject.publishAndGoToFrontend(); + const collectionWithProductContext = page.locator( + `[data-collection="${ collection.collection }"]` + ); + const queryAttribute = JSON.parse( + ( await collectionWithProductContext.getAttribute( + 'data-query' + ) ) || '{}' + ); + expect( typeof queryAttribute?.productReference ).toBe( + 'number' + ); + } ); + + test( `For collection "${ collection.name }" - changing product using inspector control`, async ( { + pageObject, + admin, + page, + editor, + } ) => { + await admin.createNewPost(); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( key as Collections ); + + // Verify that product picker is shown in Editor + const editorProductPicker = editor.canvas.locator( + SELECTORS.productPicker + ); + await expect( editorProductPicker ).toBeVisible(); + + // Once a product is selected, the product picker should be hidden + await pageObject.chooseProductInEditorProductPickerIfAvailable( + editor.canvas + ); + await expect( editorProductPicker ).toBeHidden(); + + // Verify that Album is selected + await expect( + admin.page.locator( SELECTORS.linkedProductControl.button ) + ).toContainText( 'Album' ); + + // Change product using inspector control to Beanie + await admin.page + .locator( SELECTORS.linkedProductControl.button ) + .click(); + await admin.page + .locator( SELECTORS.linkedProductControl.popoverContent ) + .getByLabel( 'Beanie', { exact: true } ) + .click(); + await expect( + admin.page.locator( SELECTORS.linkedProductControl.button ) + ).toContainText( 'Beanie' ); + + // On Frontend, verify that product reference is a number + await pageObject.publishAndGoToFrontend(); + const collectionWithProductContext = page.locator( + `[data-collection="${ collection.collection }"]` + ); + const queryAttribute = JSON.parse( + ( await collectionWithProductContext.getAttribute( + 'data-query' + ) ) || '{}' + ); + expect( typeof queryAttribute?.productReference ).toBe( + 'number' + ); + } ); + + test( `For collection "${ collection.name }" - product picker shouldn't be shown in Single Product template`, async ( { + pageObject, + admin, + editor, + } ) => { + await admin.visitSiteEditor( { + postId: `woocommerce/woocommerce//single-product`, + postType: 'wp_template', + canvas: 'edit', + } ); + await editor.canvas.locator( 'body' ).click(); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInTemplate( + key as Collections + ); + + const editorProductPicker = editor.canvas.locator( + SELECTORS.productPicker + ); + await expect( editorProductPicker ).toBeHidden(); + } ); + } + ); + + test( 'Product picker should work as expected while changing collection using "Choose collection" button from Toolbar', async ( { + pageObject, + admin, + editor, + } ) => { + await admin.createNewPost(); + await pageObject.insertProductCollection(); + await pageObject.chooseCollectionInPost( + 'myCustomCollectionWithProductContext' + ); + + // Verify that product picker is shown in Editor + const editorProductPicker = editor.canvas.locator( + SELECTORS.productPicker + ); + await expect( editorProductPicker ).toBeVisible(); + + // Once a product is selected, the product picker should be hidden + await pageObject.chooseProductInEditorProductPickerIfAvailable( + editor.canvas + ); + await expect( editorProductPicker ).toBeHidden(); + + // Change collection using Toolbar + await pageObject.changeCollectionUsingToolbar( + 'myCustomCollectionMultipleContexts' + ); + await expect( editorProductPicker ).toBeVisible(); + + // Once a product is selected, the product picker should be hidden + await pageObject.chooseProductInEditorProductPickerIfAvailable( + editor.canvas + ); + await expect( editorProductPicker ).toBeHidden(); + + // Product picker should be hidden for collections that don't need product + await pageObject.changeCollectionUsingToolbar( 'featured' ); + await expect( editorProductPicker ).toBeHidden(); + } ); +} ); diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts index 22a0fb3e3e1..1a87ebeb605 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/product-collection/product-collection.page.ts @@ -1,7 +1,7 @@ /** * External dependencies */ -import { Locator, Page } from '@playwright/test'; +import { FrameLocator, Locator, Page } from '@playwright/test'; import { Editor, Admin } from '@woocommerce/e2e-utils'; import { BlockRepresentation } from '@wordpress/e2e-test-utils-playwright/build-types/editor/insert-block'; @@ -62,6 +62,12 @@ export const SELECTORS = { previewButtonTestID: 'product-collection-preview-button', collectionPlaceholder: '[data-type="woocommerce/product-collection"] .components-placeholder', + productPicker: '.wc-blocks-product-collection__editor-product-picker', + linkedProductControl: { + button: '.wc-block-product-collection-linked-product-control__button', + popoverContent: + '.wc-block-product-collection-linked-product__popover-content', + }, }; export type Collections = @@ -200,10 +206,31 @@ class ProductCollectionPage { } } + async chooseProductInEditorProductPickerIfAvailable( + pageReference: Page | FrameLocator + ) { + const editorProductPicker = pageReference.locator( + SELECTORS.productPicker + ); + + if ( await editorProductPicker.isVisible() ) { + await editorProductPicker + .locator( 'label' ) + .filter( { + hasText: 'Album', + } ) + .click(); + } + } + async createNewPostAndInsertBlock( collection?: Collections ) { await this.admin.createNewPost(); await this.insertProductCollection(); await this.chooseCollectionInPost( collection ); + // If product picker is available, choose a product. + await this.chooseProductInEditorProductPickerIfAvailable( + this.admin.page + ); await this.refreshLocators( 'editor' ); await this.editor.openDocumentSettingsSidebar(); } @@ -345,6 +372,10 @@ class ProductCollectionPage { await this.editor.canvas.locator( 'body' ).click(); await this.insertProductCollection(); await this.chooseCollectionInTemplate( collection ); + // If product picker is available, choose a product. + await this.chooseProductInEditorProductPickerIfAvailable( + this.editor.canvas + ); await this.refreshLocators( 'editor' ); } @@ -571,6 +602,30 @@ class ProductCollectionPage { .click(); } + async changeCollectionUsingToolbar( collection: Collections ) { + // Click "Choose collection" button in the toolbar. + await this.admin.page + .getByRole( 'toolbar', { name: 'Block Tools' } ) + .getByRole( 'button', { name: 'Choose collection' } ) + .click(); + + // Select the collection from the modal. + const collectionChooserModal = this.admin.page.locator( + '.wc-blocks-product-collection__modal' + ); + await collectionChooserModal + .getByRole( 'button', { + name: collectionToButtonNameMap[ collection ], + } ) + .click(); + + await collectionChooserModal + .getByRole( 'button', { + name: 'Continue', + } ) + .click(); + } + async setDisplaySettings( { itemsPerPage, offset, diff --git a/plugins/woocommerce/changelog/50164-add-44877-context-linking-a-product-with-collection b/plugins/woocommerce/changelog/50164-add-44877-context-linking-a-product-with-collection new file mode 100644 index 00000000000..1308c1e61e7 --- /dev/null +++ b/plugins/woocommerce/changelog/50164-add-44877-context-linking-a-product-with-collection @@ -0,0 +1,4 @@ +Significance: major +Type: add + +Product Collection - Show product picker in Editor when collection requires a product but not available
        A collection can define if it requires a product context. This can be done using `usesReference` argument i.e. ```tsx __experimentalRegisterProductCollection({ ..., usesReference: ['product'], ) ``` When product context doesn't exist in current template/page/post etc. then we show product picker in Editor. This way, merchant can manually provide a product context to the collection. \ No newline at end of file diff --git a/plugins/woocommerce/changelog/50590-add-44877-context-linking-a-product-with-collection-inspector-control b/plugins/woocommerce/changelog/50590-add-44877-context-linking-a-product-with-collection-inspector-control new file mode 100644 index 00000000000..2db092dad41 --- /dev/null +++ b/plugins/woocommerce/changelog/50590-add-44877-context-linking-a-product-with-collection-inspector-control @@ -0,0 +1,4 @@ +Significance: major +Type: add + +Product Collection - Implement Inspector control to change selected product \ No newline at end of file From 0f7773dd47df90e4c7c4e60c141b307e139202cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 2 Sep 2024 09:40:47 +0200 Subject: [PATCH 173/185] Fix My Account block icon being too small when inserted via block hooks (#51047) * Fix My Account block icon being too small when inserted via block hooks * Add changelog file --- .../woocommerce/changelog/fix-50667-my-account-hooked-size | 4 ++++ plugins/woocommerce/src/Blocks/BlockTypes/CustomerAccount.php | 1 + 2 files changed, 5 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-50667-my-account-hooked-size diff --git a/plugins/woocommerce/changelog/fix-50667-my-account-hooked-size b/plugins/woocommerce/changelog/fix-50667-my-account-hooked-size new file mode 100644 index 00000000000..4fcd396ddc4 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50667-my-account-hooked-size @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix My Account block icon being too small when inserted via block hooks diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/CustomerAccount.php b/plugins/woocommerce/src/Blocks/BlockTypes/CustomerAccount.php index 80bd799b224..8d201c1051f 100644 --- a/plugins/woocommerce/src/Blocks/BlockTypes/CustomerAccount.php +++ b/plugins/woocommerce/src/Blocks/BlockTypes/CustomerAccount.php @@ -68,6 +68,7 @@ class CustomerAccount extends AbstractBlock { public function modify_hooked_block_attributes( $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ) { $parsed_hooked_block['attrs']['displayStyle'] = 'icon_only'; $parsed_hooked_block['attrs']['iconStyle'] = 'line'; + $parsed_hooked_block['attrs']['iconClass'] = 'wc-block-customer-account__account-icon'; /* * The Mini Cart block (which is hooked into the header) has a margin of 0.5em on the left side. From 74e96d689b4cd818c4dc6f764dba9a5a049400e5 Mon Sep 17 00:00:00 2001 From: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com> Date: Mon, 2 Sep 2024 11:09:56 +0100 Subject: [PATCH 174/185] [e2e tests] Tag some e2e tests to help with test audit (#51044) --- .../woocommerce/changelog/e2e-tag-e2e-tests | 4 + .../create-restricted-coupons.spec.js | 2 +- .../cart-block-calculate-shipping.spec.js | 282 +++++++++--------- .../tests/shopper/cart-block-coupons.spec.js | 218 ++++++++------ .../e2e-pw/tests/shopper/cart-block.spec.js | 224 +++++++------- .../shopper/cart-calculate-shipping.spec.js | 190 ++++++------ .../cart-checkout-block-calculate-tax.spec.js | 8 +- .../cart-checkout-calculate-tax.spec.js | 2 +- .../shopper/cart-checkout-coupons.spec.js | 95 +++--- .../cart-checkout-restricted-coupons.spec.js | 2 +- .../tests/shopper/cart-redirection.spec.js | 2 +- .../tests/e2e-pw/tests/shopper/cart.spec.js | 170 ++++++----- .../tests/shopper/launch-your-store.spec.js | 84 +++--- .../shopper/shop-title-after-deletion.spec.js | 2 +- .../tests/shopper/wordpress-post.spec.js | 2 +- 15 files changed, 684 insertions(+), 603 deletions(-) create mode 100644 plugins/woocommerce/changelog/e2e-tag-e2e-tests diff --git a/plugins/woocommerce/changelog/e2e-tag-e2e-tests b/plugins/woocommerce/changelog/e2e-tag-e2e-tests new file mode 100644 index 00000000000..4f73f5cc6c2 --- /dev/null +++ b/plugins/woocommerce/changelog/e2e-tag-e2e-tests @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + + diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js index 7a94c6deb02..dd6941c6cc9 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js @@ -96,7 +96,7 @@ const test = baseTest.extend( { }, } ); -test.describe( 'Restricted coupon management', { tag: '@services' }, () => { +test.describe( 'Restricted coupon management', { tag: [ '@services' ] }, () => { for ( const couponType of Object.keys( couponData ) ) { test( `can create new ${ couponType } coupon`, async ( { page, diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-calculate-shipping.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-calculate-shipping.spec.js index 8649bd7e246..2b736893759 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-calculate-shipping.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-calculate-shipping.spec.js @@ -130,157 +130,173 @@ test.describe( } ); } ); - test( 'allows customer to calculate Free Shipping in cart block if in Netherlands', async ( { - page, - context, - cartBlockPage, - } ) => { - await context.clearCookies(); + test( + 'allows customer to calculate Free Shipping in cart block if in Netherlands', + { tag: [ '@could-be-unit-test' ] }, + async ( { page, context, cartBlockPage } ) => { + await context.clearCookies(); - await addAProductToCart( page, product1Id ); - await page.goto( cartBlockPage.slug ); + await addAProductToCart( page, product1Id ); + await page.goto( cartBlockPage.slug ); - // Set shipping country to Netherlands - await page.getByLabel( 'Add an address for shipping' ).click(); - await page - .getByRole( 'combobox' ) - .first() - .selectOption( 'Netherlands' ); - await page.getByLabel( 'Postal code' ).fill( '1011AA' ); - await page.getByLabel( 'City' ).fill( 'Amsterdam' ); - await page.getByRole( 'button', { name: 'Update' } ).click(); + // Set shipping country to Netherlands + await page.getByLabel( 'Add an address for shipping' ).click(); + await page + .getByRole( 'combobox' ) + .first() + .selectOption( 'Netherlands' ); + await page.getByLabel( 'Postal code' ).fill( '1011AA' ); + await page.getByLabel( 'City' ).fill( 'Amsterdam' ); + await page.getByRole( 'button', { name: 'Update' } ).click(); - // Verify shipping costs - await expect( - page.getByRole( 'group' ).getByText( 'Free shipping' ) - ).toBeVisible(); - await expect( - page.getByRole( 'strong' ).getByText( 'Free', { exact: true } ) - ).toBeVisible(); - await expect( page.getByText( '$' ).nth( 2 ) ).toContainText( - firstProductPrice - ); - } ); + // Verify shipping costs + await expect( + page.getByRole( 'group' ).getByText( 'Free shipping' ) + ).toBeVisible(); + await expect( + page + .getByRole( 'strong' ) + .getByText( 'Free', { exact: true } ) + ).toBeVisible(); + await expect( page.getByText( '$' ).nth( 2 ) ).toContainText( + firstProductPrice + ); + } + ); - test( 'allows customer to calculate Flat rate and Local pickup in cart block if in Portugal', async ( { - page, - context, - cartBlockPage, - } ) => { - await context.clearCookies(); + test( + 'allows customer to calculate Flat rate and Local pickup in cart block if in Portugal', + { tag: [ '@could-be-unit-test' ] }, + async ( { page, context, cartBlockPage } ) => { + await context.clearCookies(); - await addAProductToCart( page, product1Id ); - await page.goto( cartBlockPage.slug ); + await addAProductToCart( page, product1Id ); + await page.goto( cartBlockPage.slug ); - // Set shipping country to Portugal - await page.getByLabel( 'Add an address for shipping' ).click(); - await page - .getByRole( 'combobox' ) - .first() - .selectOption( 'Portugal' ); - await page.getByLabel( 'Postal code' ).fill( '1000-001' ); - await page.getByLabel( 'City' ).fill( 'Lisbon' ); - await page.getByRole( 'button', { name: 'Update' } ).click(); + // Set shipping country to Portugal + await page.getByLabel( 'Add an address for shipping' ).click(); + await page + .getByRole( 'combobox' ) + .first() + .selectOption( 'Portugal' ); + await page.getByLabel( 'Postal code' ).fill( '1000-001' ); + await page.getByLabel( 'City' ).fill( 'Lisbon' ); + await page.getByRole( 'button', { name: 'Update' } ).click(); - // Verify shipping costs - await expect( - page.getByRole( 'group' ).getByText( 'Flat rate' ) - ).toBeVisible(); - await expect( page.getByText( 'Shipping$5.00Flat' ) ).toBeVisible(); - await expect( - page.getByText( `$${ firstProductWithFlatRate }` ) - ).toBeVisible(); + // Verify shipping costs + await expect( + page.getByRole( 'group' ).getByText( 'Flat rate' ) + ).toBeVisible(); + await expect( + page.getByText( 'Shipping$5.00Flat' ) + ).toBeVisible(); + await expect( + page.getByText( `$${ firstProductWithFlatRate }` ) + ).toBeVisible(); - // Set shipping to local pickup instead of flat rate - await page.getByRole( 'group' ).getByText( 'Local pickup' ).click(); + // Set shipping to local pickup instead of flat rate + await page + .getByRole( 'group' ) + .getByText( 'Local pickup' ) + .click(); - // Verify updated shipping costs - await expect( page.getByText( 'ShippingFreeLocal' ) ).toBeVisible(); - await expect( page.getByText( '$' ).nth( 2 ) ).toContainText( - firstProductPrice - ); - } ); + // Verify updated shipping costs + await expect( + page.getByText( 'ShippingFreeLocal' ) + ).toBeVisible(); + await expect( page.getByText( '$' ).nth( 2 ) ).toContainText( + firstProductPrice + ); + } + ); - test( 'should show correct total cart block price after updating quantity', async ( { - page, - context, - cartBlockPage, - } ) => { - await context.clearCookies(); + test( + 'should show correct total cart block price after updating quantity', + { tag: [ '@could-be-unit-test' ] }, + async ( { page, context, cartBlockPage } ) => { + await context.clearCookies(); - await addAProductToCart( page, product1Id ); - await page.goto( cartBlockPage.slug ); + await addAProductToCart( page, product1Id ); + await page.goto( cartBlockPage.slug ); - // Set shipping country to Portugal - await page.getByLabel( 'Add an address for shipping' ).click(); - await page - .getByRole( 'combobox' ) - .first() - .selectOption( 'Portugal' ); - await page.getByLabel( 'Postal code' ).fill( '1000-001' ); - await page.getByLabel( 'City' ).fill( 'Lisbon' ); - await page.getByRole( 'button', { name: 'Update' } ).click(); + // Set shipping country to Portugal + await page.getByLabel( 'Add an address for shipping' ).click(); + await page + .getByRole( 'combobox' ) + .first() + .selectOption( 'Portugal' ); + await page.getByLabel( 'Postal code' ).fill( '1000-001' ); + await page.getByLabel( 'City' ).fill( 'Lisbon' ); + await page.getByRole( 'button', { name: 'Update' } ).click(); - // Increase product quantity and verify the updated price - await page.getByLabel( 'Increase quantity of First' ).click(); - await expect( - page.getByText( - `$${ - parseInt( firstProductPrice, 10 ) + - parseInt( firstProductPrice, 10 ) + - 5 - }`.toString() - ) - ).toBeVisible(); - } ); + // Increase product quantity and verify the updated price + await page.getByLabel( 'Increase quantity of First' ).click(); + await expect( + page.getByText( + `$${ + parseInt( firstProductPrice, 10 ) + + parseInt( firstProductPrice, 10 ) + + 5 + }`.toString() + ) + ).toBeVisible(); + } + ); - test( 'should show correct total cart block price with 2 different products and flat rate/local pickup', async ( { - page, - context, - cartBlockPage, - } ) => { - await context.clearCookies(); + test( + 'should show correct total cart block price with 2 different products and flat rate/local pickup', + { tag: [ '@could-be-unit-test' ] }, + async ( { page, context, cartBlockPage } ) => { + await context.clearCookies(); - await addAProductToCart( page, product1Id ); - await addAProductToCart( page, product2Id ); - await page.goto( cartBlockPage.slug ); + await addAProductToCart( page, product1Id ); + await addAProductToCart( page, product2Id ); + await page.goto( cartBlockPage.slug ); - // Set shipping country to Portugal - await page.getByLabel( 'Add an address for shipping' ).click(); - await page - .getByRole( 'combobox' ) - .first() - .selectOption( 'Portugal' ); - await page.getByLabel( 'Postal code' ).fill( '1000-001' ); - await page.getByLabel( 'City' ).fill( 'Lisbon' ); - await page.getByRole( 'button', { name: 'Update' } ).click(); + // Set shipping country to Portugal + await page.getByLabel( 'Add an address for shipping' ).click(); + await page + .getByRole( 'combobox' ) + .first() + .selectOption( 'Portugal' ); + await page.getByLabel( 'Postal code' ).fill( '1000-001' ); + await page.getByLabel( 'City' ).fill( 'Lisbon' ); + await page.getByRole( 'button', { name: 'Update' } ).click(); - // Verify shipping costs - await expect( - page.getByRole( 'group' ).getByText( 'Flat rate' ) - ).toBeVisible(); - await expect( page.getByText( 'Shipping$5.00Flat' ) ).toBeVisible(); - await expect( - page.getByText( - `$${ - parseInt( firstProductPrice, 10 ) + - parseInt( secondProductPrice, 10 ) + - 5 - }`.toString() - ) - ).toBeVisible(); + // Verify shipping costs + await expect( + page.getByRole( 'group' ).getByText( 'Flat rate' ) + ).toBeVisible(); + await expect( + page.getByText( 'Shipping$5.00Flat' ) + ).toBeVisible(); + await expect( + page.getByText( + `$${ + parseInt( firstProductPrice, 10 ) + + parseInt( secondProductPrice, 10 ) + + 5 + }`.toString() + ) + ).toBeVisible(); - // Set shipping to local pickup instead of flat rate - await page.getByRole( 'group' ).getByText( 'Local pickup' ).click(); + // Set shipping to local pickup instead of flat rate + await page + .getByRole( 'group' ) + .getByText( 'Local pickup' ) + .click(); - // Verify updated shipping costs - await expect( page.getByText( 'ShippingFreeLocal' ) ).toBeVisible(); - await expect( - page - .locator( 'div' ) - .filter( { hasText: /^\$30\.00$/ } ) - .locator( 'span' ) - ).toBeVisible(); - } ); + // Verify updated shipping costs + await expect( + page.getByText( 'ShippingFreeLocal' ) + ).toBeVisible(); + await expect( + page + .locator( 'div' ) + .filter( { hasText: /^\$30\.00$/ } ) + .locator( 'span' ) + ).toBeVisible(); + } + ); } ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js index 62d8d6f2cdc..9d709e40ea9 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block-coupons.spec.js @@ -127,17 +127,111 @@ test.describe( } ); } ); - test( 'allows cart block to apply coupon of any type', async ( { - page, - } ) => { - const totals = [ '$50.00', '$27.50', '$45.00' ]; + test( + 'allows cart block to apply coupon of any type', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + const totals = [ '$50.00', '$27.50', '$45.00' ]; - // apply all coupon types - for ( let i = 0; i < coupons.length; i++ ) { + // apply all coupon types + for ( let i = 0; i < coupons.length; i++ ) { + await page + .getByRole( 'button', { name: 'Add a coupon' } ) + .click(); + await page + .getByLabel( 'Enter code' ) + .fill( coupons[ i ].code ); + await page.getByText( 'Apply', { exact: true } ).click(); + await expect( + page + .locator( + '.wc-block-components-notice-banner__content' + ) + .getByText( + `Coupon code "${ coupons[ i ].code }" has been applied to your cart.` + ) + ).toBeVisible(); + await expect( + page.locator( + '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' + ) + ).toHaveText( totals[ i ] ); + await page + .getByLabel( `Remove coupon "${ coupons[ i ].code }"` ) + .click(); + await expect( + page + .locator( + '.wc-block-components-notice-banner__content' + ) + .getByText( + `Coupon code "${ coupons[ i ].code }" has been removed from your cart.` + ) + ).toBeVisible(); + } + } + ); + + test( + 'allows cart block to apply multiple coupons', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + const totals = [ '$50.00', '$22.50', '$12.50' ]; + const totalsReverse = [ '$17.50', '$45.00', '$55.00' ]; + const discounts = [ '-$5.00', '-$32.50', '-$42.50' ]; + + // add all coupons and verify prices + for ( let i = 0; i < coupons.length; i++ ) { + await page + .getByRole( 'button', { name: 'Add a coupon' } ) + .click(); + await page + .getByLabel( 'Enter code' ) + .fill( coupons[ i ].code ); + await page.getByText( 'Apply', { exact: true } ).click(); + await expect( + page + .locator( + '.wc-block-components-notice-banner__content' + ) + .getByText( + `Coupon code "${ coupons[ i ].code }" has been applied to your cart.` + ) + ).toBeVisible(); + await expect( + page.locator( + '.wc-block-components-totals-discount > .wc-block-components-totals-item__value' + ) + ).toHaveText( discounts[ i ] ); + await expect( + page.locator( + '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' + ) + ).toHaveText( totals[ i ] ); + } + + for ( let i = 0; i < coupons.length; i++ ) { + await page + .getByLabel( `Remove coupon "${ coupons[ i ].code }"` ) + .click(); + await expect( + page.locator( + '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' + ) + ).toHaveText( totalsReverse[ i ] ); + } + } + ); + + test( + 'prevents cart block applying same coupon twice', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + // try to add two same coupons and verify the error message await page .getByRole( 'button', { name: 'Add a coupon' } ) .click(); - await page.getByLabel( 'Enter code' ).fill( coupons[ i ].code ); + await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code ); await page.getByText( 'Apply', { exact: true } ).click(); await expect( page @@ -145,114 +239,40 @@ test.describe( '.wc-block-components-notice-banner__content' ) .getByText( - `Coupon code "${ coupons[ i ].code }" has been applied to your cart.` + `Coupon code "${ coupons[ 0 ].code }" has been applied to your cart.` ) ).toBeVisible(); - await expect( - page.locator( - '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' - ) - ).toHaveText( totals[ i ] ); - await page - .getByLabel( `Remove coupon "${ coupons[ i ].code }"` ) - .click(); - await expect( - page - .locator( - '.wc-block-components-notice-banner__content' - ) - .getByText( - `Coupon code "${ coupons[ i ].code }" has been removed from your cart.` - ) - ).toBeVisible(); - } - } ); - - test( 'allows cart block to apply multiple coupons', async ( { - page, - } ) => { - const totals = [ '$50.00', '$22.50', '$12.50' ]; - const totalsReverse = [ '$17.50', '$45.00', '$55.00' ]; - const discounts = [ '-$5.00', '-$32.50', '-$42.50' ]; - - // add all coupons and verify prices - for ( let i = 0; i < coupons.length; i++ ) { await page .getByRole( 'button', { name: 'Add a coupon' } ) .click(); - await page.getByLabel( 'Enter code' ).fill( coupons[ i ].code ); + await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code ); await page.getByText( 'Apply', { exact: true } ).click(); await expect( page - .locator( - '.wc-block-components-notice-banner__content' - ) + .getByRole( 'alert' ) .getByText( - `Coupon code "${ coupons[ i ].code }" has been applied to your cart.` + `Coupon code "${ coupons[ 0 ].code }" has already been applied.` ) ).toBeVisible(); - await expect( - page.locator( - '.wc-block-components-totals-discount > .wc-block-components-totals-item__value' - ) - ).toHaveText( discounts[ i ] ); - await expect( - page.locator( - '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' - ) - ).toHaveText( totals[ i ] ); } + ); - for ( let i = 0; i < coupons.length; i++ ) { + test( + 'prevents cart block applying coupon with usage limit', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + // add coupon with usage limit await page - .getByLabel( `Remove coupon "${ coupons[ i ].code }"` ) + .getByRole( 'button', { name: 'Add a coupon' } ) .click(); + await page.getByLabel( 'Enter code' ).fill( couponLimitedCode ); + await page.getByText( 'Apply', { exact: true } ).click(); await expect( - page.locator( - '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' - ) - ).toHaveText( totalsReverse[ i ] ); + page + .getByRole( 'alert' ) + .getByText( 'Coupon usage limit has been reached.' ) + ).toBeVisible(); } - } ); - - test( 'prevents cart block applying same coupon twice', async ( { - page, - } ) => { - // try to add two same coupons and verify the error message - await page.getByRole( 'button', { name: 'Add a coupon' } ).click(); - await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code ); - await page.getByText( 'Apply', { exact: true } ).click(); - await expect( - page - .locator( '.wc-block-components-notice-banner__content' ) - .getByText( - `Coupon code "${ coupons[ 0 ].code }" has been applied to your cart.` - ) - ).toBeVisible(); - await page.getByRole( 'button', { name: 'Add a coupon' } ).click(); - await page.getByLabel( 'Enter code' ).fill( coupons[ 0 ].code ); - await page.getByText( 'Apply', { exact: true } ).click(); - await expect( - page - .getByRole( 'alert' ) - .getByText( - `Coupon code "${ coupons[ 0 ].code }" has already been applied.` - ) - ).toBeVisible(); - } ); - - test( 'prevents cart block applying coupon with usage limit', async ( { - page, - } ) => { - // add coupon with usage limit - await page.getByRole( 'button', { name: 'Add a coupon' } ).click(); - await page.getByLabel( 'Enter code' ).fill( couponLimitedCode ); - await page.getByText( 'Apply', { exact: true } ).click(); - await expect( - page - .getByRole( 'alert' ) - .getByText( 'Coupon usage limit has been reached.' ) - ).toBeVisible(); - } ); + ); } ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block.spec.js index 11ab6abe7d9..3ce134b9e9c 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-block.spec.js @@ -73,116 +73,132 @@ test.describe( 'Cart Block page', { tag: [ '@payments', '@services' ] }, () => { } ); } ); - test( 'can see empty cart, add and remove simple & cross sell product, increase to max quantity', async ( { - page, - testPage, - } ) => { - await goToPageEditor( { page } ); - await fillPageTitle( page, testPage.title ); - await insertBlockByShortcut( page, 'Cart' ); - await publishPage( page, testPage.title ); + test( + 'can see empty cart, add and remove simple & cross sell product, increase to max quantity', + { tag: [ '@could-be-unit-test' ] }, + async ( { page, testPage } ) => { + await goToPageEditor( { page } ); + await fillPageTitle( page, testPage.title ); + await insertBlockByShortcut( page, 'Cart' ); + await publishPage( page, testPage.title ); - // go to the page to test empty cart block - await page.goto( testPage.slug ); - await expect( - page.getByRole( 'heading', { name: testPage.title } ) - ).toBeVisible(); - await expect( - await page.getByText( 'Your cart is currently empty!' ).count() - ).toBeGreaterThan( 0 ); - await expect( - page.getByRole( 'link', { name: 'Browse store' } ) - ).toBeVisible(); - await page.getByRole( 'link', { name: 'Browse store' } ).click(); - await expect( - page.getByRole( 'heading', { name: 'Shop' } ) - ).toBeVisible(); + // go to the page to test empty cart block + await page.goto( testPage.slug ); + await expect( + page.getByRole( 'heading', { name: testPage.title } ) + ).toBeVisible(); + await expect( + await page.getByText( 'Your cart is currently empty!' ).count() + ).toBeGreaterThan( 0 ); + await expect( + page.getByRole( 'link', { name: 'Browse store' } ) + ).toBeVisible(); + await page.getByRole( 'link', { name: 'Browse store' } ).click(); + await expect( + page.getByRole( 'heading', { name: 'Shop' } ) + ).toBeVisible(); - await addAProductToCart( page, product1Id ); - await page.goto( testPage.slug ); - await expect( - page.getByRole( 'heading', { name: testPage.title } ) - ).toBeVisible(); - await expect( - page.getByRole( 'link', { name: simpleProductName, exact: true } ) - ).toBeVisible(); - await expect( page.getByText( simpleProductDesc ) ).toBeVisible(); - await expect( - page.getByText( `Save $${ singleProductSalePrice }` ) - ).toBeVisible(); + await addAProductToCart( page, product1Id ); + await page.goto( testPage.slug ); + await expect( + page.getByRole( 'heading', { name: testPage.title } ) + ).toBeVisible(); + await expect( + page.getByRole( 'link', { + name: simpleProductName, + exact: true, + } ) + ).toBeVisible(); + await expect( page.getByText( simpleProductDesc ) ).toBeVisible(); + await expect( + page.getByText( `Save $${ singleProductSalePrice }` ) + ).toBeVisible(); - // increase product quantity to its maximum - await expect( page.getByText( '2 left in stock' ) ).toBeVisible(); - await page - .getByRole( 'button' ) - .filter( { hasText: '+', exact: true } ) - .click(); - await expect( - page.locator( - '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' - ) - ).toContainText( `$${ doubleProductsPrice.toString() }` ); - await expect( - page.getByRole( 'button' ).filter( { hasText: '+', exact: true } ) - ).toBeDisabled(); + // increase product quantity to its maximum + await expect( page.getByText( '2 left in stock' ) ).toBeVisible(); + await page + .getByRole( 'button' ) + .filter( { hasText: '+', exact: true } ) + .click(); + await expect( + page.locator( + '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' + ) + ).toContainText( `$${ doubleProductsPrice.toString() }` ); + await expect( + page + .getByRole( 'button' ) + .filter( { hasText: '+', exact: true } ) + ).toBeDisabled(); - // add cross-sell products to cart - await expect( - page.getByRole( 'heading', { name: 'You may be interested in…' } ) - ).toBeVisible(); - await page - .getByLabel( `Add to cart: “${ simpleProductName } Cross-Sell 1”` ) - .click(); - await expect( - page - .locator( '.wc-block-cart-items' ) - .getByText( `${ simpleProductName } Cross-Sell 1` ) - ).toBeVisible(); - await page - .getByLabel( `Add to cart: “${ simpleProductName } Cross-Sell 2”` ) - .click(); - await expect( - page - .locator( '.wc-block-cart-items' ) - .getByText( `${ simpleProductName } Cross-Sell 2` ) - ).toBeVisible(); + // add cross-sell products to cart + await expect( + page.getByRole( 'heading', { + name: 'You may be interested in…', + } ) + ).toBeVisible(); + await page + .getByLabel( + `Add to cart: “${ simpleProductName } Cross-Sell 1”` + ) + .click(); + await expect( + page + .locator( '.wc-block-cart-items' ) + .getByText( `${ simpleProductName } Cross-Sell 1` ) + ).toBeVisible(); + await page + .getByLabel( + `Add to cart: “${ simpleProductName } Cross-Sell 2”` + ) + .click(); + await expect( + page + .locator( '.wc-block-cart-items' ) + .getByText( `${ simpleProductName } Cross-Sell 2` ) + ).toBeVisible(); - await page.goto( testPage.slug ); - await expect( - page.getByRole( 'heading', { name: testPage.title } ) - ).toBeVisible(); - await expect( - page.getByRole( 'heading', { name: 'You may be interested in…' } ) - ).toBeHidden(); - await expect( - page.locator( - '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' - ) - ).toContainText( - `$${ singleProductWithCrossSellProducts.toString() }` - ); + await page.goto( testPage.slug ); + await expect( + page.getByRole( 'heading', { name: testPage.title } ) + ).toBeVisible(); + await expect( + page.getByRole( 'heading', { + name: 'You may be interested in…', + } ) + ).toBeHidden(); + await expect( + page.locator( + '.wc-block-components-totals-footer-item > .wc-block-components-totals-item__value' + ) + ).toContainText( + `$${ singleProductWithCrossSellProducts.toString() }` + ); - // remove cross-sell products from cart - await page.locator( ':nth-match(:text("Remove item"), 3)' ).click(); - await page.locator( ':nth-match(:text("Remove item"), 2)' ).click(); - await expect( - page.getByRole( 'heading', { name: 'You may be interested in…' } ) - ).toBeVisible(); + // remove cross-sell products from cart + await page.locator( ':nth-match(:text("Remove item"), 3)' ).click(); + await page.locator( ':nth-match(:text("Remove item"), 2)' ).click(); + await expect( + page.getByRole( 'heading', { + name: 'You may be interested in…', + } ) + ).toBeVisible(); - // check if the link to proceed to the checkout exists - await expect( - page.getByRole( 'link', { - name: 'Proceed to Checkout', - } ) - ).toBeVisible(); + // check if the link to proceed to the checkout exists + await expect( + page.getByRole( 'link', { + name: 'Proceed to Checkout', + } ) + ).toBeVisible(); - // remove product from cart - await page.locator( ':text("Remove item")' ).click(); - await expect( - page.getByText( 'Your cart is currently empty!' ) - ).toBeVisible(); - await expect( - page.getByRole( 'link', { name: 'Browse store' } ) - ).toBeVisible(); - } ); + // remove product from cart + await page.locator( ':text("Remove item")' ).click(); + await expect( + page.getByText( 'Your cart is currently empty!' ) + ).toBeVisible(); + await expect( + page.getByRole( 'link', { name: 'Browse store' } ) + ).toBeVisible(); + } + ); } ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-calculate-shipping.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-calculate-shipping.spec.js index 62be5e273a3..4f3d0026b88 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-calculate-shipping.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-calculate-shipping.spec.js @@ -125,108 +125,120 @@ test.describe( } ); } ); - test( 'allows customer to calculate Free Shipping if in Germany', async ( { - page, - } ) => { - await page.goto( '/cart/' ); - // Set shipping country to Germany - await page.locator( 'a.shipping-calculator-button' ).click(); - await page - .locator( '#calc_shipping_country' ) - .selectOption( shippingCountryDE ); - await page.locator( 'button[name="calc_shipping"]' ).click(); + test( + 'allows customer to calculate Free Shipping if in Germany', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await page.goto( '/cart/' ); + // Set shipping country to Germany + await page.locator( 'a.shipping-calculator-button' ).click(); + await page + .locator( '#calc_shipping_country' ) + .selectOption( shippingCountryDE ); + await page.locator( 'button[name="calc_shipping"]' ).click(); - // Verify shipping costs - await expect( - page.locator( '.shipping ul#shipping_method > li' ) - ).toContainText( 'Free shipping' ); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( firstProductPrice ); - } ); + // Verify shipping costs + await expect( + page.locator( '.shipping ul#shipping_method > li' ) + ).toContainText( 'Free shipping' ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( firstProductPrice ); + } + ); - test( 'allows customer to calculate Flat rate and Local pickup if in France', async ( { - page, - } ) => { - await page.goto( '/cart/' ); - // Set shipping country to France - await page.locator( 'a.shipping-calculator-button' ).click(); - await page - .locator( '#calc_shipping_country' ) - .selectOption( shippingCountryFR ); - await page.locator( 'button[name="calc_shipping"]' ).click(); + test( + 'allows customer to calculate Flat rate and Local pickup if in France', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await page.goto( '/cart/' ); + // Set shipping country to France + await page.locator( 'a.shipping-calculator-button' ).click(); + await page + .locator( '#calc_shipping_country' ) + .selectOption( shippingCountryFR ); + await page.locator( 'button[name="calc_shipping"]' ).click(); - // Verify shipping costs - await expect( page.locator( '.shipping .amount' ) ).toContainText( - '$5.00' - ); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( `$${ firstProductWithFlatRate }` ); + // Verify shipping costs + await expect( + page.locator( '.shipping .amount' ) + ).toContainText( '$5.00' ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( `$${ firstProductWithFlatRate }` ); - // Set shipping to local pickup instead of flat rate - await page.locator( 'text=Local pickup' ).click(); + // Set shipping to local pickup instead of flat rate + await page.locator( 'text=Local pickup' ).click(); - // Verify updated shipping costs - await expect( - page.locator( '.order-total .amount' ).first() - ).toContainText( `$${ firstProductPrice }` ); - } ); + // Verify updated shipping costs + await expect( + page.locator( '.order-total .amount' ).first() + ).toContainText( `$${ firstProductPrice }` ); + } + ); - test( 'should show correct total cart price after updating quantity', async ( { - page, - } ) => { - await page.goto( '/cart/' ); - await page.locator( 'input.qty' ).fill( '4' ); - await page.locator( 'text=Update cart' ).click(); + test( + 'should show correct total cart price after updating quantity', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await page.goto( '/cart/' ); + await page.locator( 'input.qty' ).fill( '4' ); + await page.locator( 'text=Update cart' ).click(); - // Set shipping country to France - await page.locator( 'a.shipping-calculator-button' ).click(); - await page - .locator( '#calc_shipping_country' ) - .selectOption( shippingCountryFR ); - await page.locator( 'button[name="calc_shipping"]' ).click(); + // Set shipping country to France + await page.locator( 'a.shipping-calculator-button' ).click(); + await page + .locator( '#calc_shipping_country' ) + .selectOption( shippingCountryFR ); + await page.locator( 'button[name="calc_shipping"]' ).click(); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( `$${ fourProductsWithFlatRate }` ); - } ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( `$${ fourProductsWithFlatRate }` ); + } + ); - test( 'should show correct total cart price with 2 products and flat rate', async ( { - page, - } ) => { - await addAProductToCart( page, secondProductId ); + test( + 'should show correct total cart price with 2 products and flat rate', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await addAProductToCart( page, secondProductId ); - await page.goto( '/cart/' ); - await page.locator( 'a.shipping-calculator-button' ).click(); - await page - .locator( '#calc_shipping_country' ) - .selectOption( shippingCountryFR ); - await page.locator( 'button[name="calc_shipping"]' ).click(); + await page.goto( '/cart/' ); + await page.locator( 'a.shipping-calculator-button' ).click(); + await page + .locator( '#calc_shipping_country' ) + .selectOption( shippingCountryFR ); + await page.locator( 'button[name="calc_shipping"]' ).click(); - await expect( page.locator( '.shipping .amount' ) ).toContainText( - '$5.00' - ); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( `$${ twoProductsWithFlatRate }` ); - } ); + await expect( + page.locator( '.shipping .amount' ) + ).toContainText( '$5.00' ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( `$${ twoProductsWithFlatRate }` ); + } + ); - test( 'should show correct total cart price with 2 products without flat rate', async ( { - page, - } ) => { - await addAProductToCart( page, secondProductId ); + test( + 'should show correct total cart price with 2 products without flat rate', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await addAProductToCart( page, secondProductId ); - // Set shipping country to Spain - await page.goto( '/cart/' ); - await page.locator( 'a.shipping-calculator-button' ).click(); - await page.locator( '#calc_shipping_country' ).selectOption( 'ES' ); - await page.locator( 'button[name="calc_shipping"]' ).click(); + // Set shipping country to Spain + await page.goto( '/cart/' ); + await page.locator( 'a.shipping-calculator-button' ).click(); + await page + .locator( '#calc_shipping_country' ) + .selectOption( 'ES' ); + await page.locator( 'button[name="calc_shipping"]' ).click(); - // Verify shipping costs - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( `$${ twoProductsTotal }` ); - } ); + // Verify shipping costs + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( `$${ twoProductsTotal }` ); + } + ); } ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-block-calculate-tax.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-block-calculate-tax.spec.js index f449ebe1b3a..eb189618973 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-block-calculate-tax.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-block-calculate-tax.spec.js @@ -38,7 +38,7 @@ let productId, test.describe( 'Shopper Cart & Checkout Block Tax Display', - { tag: [ '@payments', '@services', '@hpos' ] }, + { tag: [ '@payments', '@services', '@hpos', '@could-be-unit-test' ] }, () => { test.use( { storageState: process.env.ADMINSTATE } ); test.beforeAll( async ( { baseURL } ) => { @@ -240,7 +240,7 @@ test.describe( test.describe( 'Shopper Cart & Checkout Block Tax Rounding', - { tag: [ '@payments', '@services' ] }, + { tag: [ '@payments', '@services', '@could-be-unit-test' ] }, () => { test.beforeAll( async ( { baseURL } ) => { const api = new wcApi( { @@ -484,7 +484,7 @@ test.describe( test.describe( 'Shopper Cart & Checkout Block Tax Levels', - { tag: [ '@payments', '@services' ] }, + { tag: [ '@payments', '@services', '@could-be-unit-test' ] }, () => { test.beforeAll( async ( { baseURL } ) => { const api = new wcApi( { @@ -809,7 +809,7 @@ test.describe( test.describe( 'Shipping Cart & Checkout Block Tax', - { tag: [ '@payments', '@services' ] }, + { tag: [ '@payments', '@services', '@could-be-unit-test' ] }, () => { test.beforeAll( async ( { baseURL } ) => { const api = new wcApi( { diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-calculate-tax.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-calculate-tax.spec.js index bfcc1218a69..f5f1b416487 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-calculate-tax.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-calculate-tax.spec.js @@ -24,7 +24,7 @@ let productId, test.describe.serial( 'Tax rates in the cart and checkout', - { tag: [ '@payments', '@services', '@hpos' ] }, + { tag: [ '@payments', '@services', '@hpos', '@could-be-unit-test' ] }, () => { test.beforeAll( async ( { baseURL } ) => { const api = new wcApi( { diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-coupons.spec.js index 813b3623236..6301a750e90 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-coupons.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-coupons.spec.js @@ -306,60 +306,65 @@ test.describe( } ); } ); - test( 'restores total when coupons are removed', async ( { - page, - context, - } ) => { - await test.step( 'Load cart page and try restoring total when removed coupons', async () => { - await addAProductToCart( page, firstProductId ); + test( + 'restores total when coupons are removed', + { tag: [ '@could-be-unit-test' ] }, + async ( { page, context } ) => { + await test.step( 'Load cart page and try restoring total when removed coupons', async () => { + await addAProductToCart( page, firstProductId ); - await page.goto( '/cart/' ); - await page.locator( '#coupon_code' ).fill( coupons[ 0 ].code ); - await page - .getByRole( 'button', { name: 'Apply coupon' } ) - .click(); + await page.goto( '/cart/' ); + await page + .locator( '#coupon_code' ) + .fill( coupons[ 0 ].code ); + await page + .getByRole( 'button', { name: 'Apply coupon' } ) + .click(); - // confirm numbers - await expect( - page.locator( '.cart-discount .amount' ) - ).toContainText( discounts[ 0 ] ); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( totals[ 0 ] ); + // confirm numbers + await expect( + page.locator( '.cart-discount .amount' ) + ).toContainText( discounts[ 0 ] ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( totals[ 0 ] ); - await page.locator( 'a.woocommerce-remove-coupon' ).click(); + await page.locator( 'a.woocommerce-remove-coupon' ).click(); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( '$20.00' ); - } ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( '$20.00' ); + } ); - await context.clearCookies(); + await context.clearCookies(); - await test.step( 'Load checkout page and try restoring total when removed coupons', async () => { - await addAProductToCart( page, firstProductId ); + await test.step( 'Load checkout page and try restoring total when removed coupons', async () => { + await addAProductToCart( page, firstProductId ); - await page.goto( '/checkout/' ); - await page - .locator( 'text=Click here to enter your code' ) - .click(); - await page.locator( '#coupon_code' ).fill( coupons[ 0 ].code ); - await page.locator( 'text=Apply coupon' ).click(); + await page.goto( '/checkout/' ); + await page + .locator( 'text=Click here to enter your code' ) + .click(); + await page + .locator( '#coupon_code' ) + .fill( coupons[ 0 ].code ); + await page.locator( 'text=Apply coupon' ).click(); - // confirm numbers - await expect( - page.locator( '.cart-discount .amount' ) - ).toContainText( discounts[ 0 ] ); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( totals[ 0 ] ); + // confirm numbers + await expect( + page.locator( '.cart-discount .amount' ) + ).toContainText( discounts[ 0 ] ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( totals[ 0 ] ); - await page.locator( 'a.woocommerce-remove-coupon' ).click(); + await page.locator( 'a.woocommerce-remove-coupon' ).click(); - await expect( - page.locator( '.order-total .amount' ) - ).toContainText( '$20.00' ); - } ); - } ); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( '$20.00' ); + } ); + } + ); } ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js index 172c1e845a5..8ee5ca1d5e3 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-checkout-restricted-coupons.spec.js @@ -17,7 +17,7 @@ const awaitCartPageResponse = ( page ) => test.describe( 'Cart & Checkout Restricted Coupons', - { tag: [ '@payments', '@services', '@hpos' ] }, + { tag: [ '@payments', '@services', '@hpos', '@could-be-unit-test' ] }, () => { let firstProductId, secondProductId, diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-redirection.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-redirection.spec.js index 869a9cd0c5f..186b7965e3e 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-redirection.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart-redirection.spec.js @@ -3,7 +3,7 @@ const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default; test.describe( 'Cart > Redirect to cart from shop', - { tag: [ '@payments', '@services' ] }, + { tag: [ '@payments', '@services', '@not-e2e' ] }, () => { let productId; const productName = 'A redirect product test'; diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart.spec.js index f1dcdeeebd5..58b7a58c68f 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/cart.spec.js @@ -81,100 +81,116 @@ test.describe( 'Cart page', { tag: [ '@payments', '@services' ] }, () => { await responsePromise; } - test( 'should display no item in the cart', async ( { page } ) => { - await page.goto( '/cart/' ); - await expect( - page.getByText( 'Your cart is currently empty.' ) - ).toBeVisible(); - } ); - - test( 'should add the product to the cart from the shop page', async ( { - page, - } ) => { - await goToShopPageAndAddProductToCart( page, productName ); - - await page.goto( '/cart/' ); - await expect( page.locator( 'td.product-name' ) ).toContainText( - productName - ); - } ); - - test( 'should increase item quantity when "Add to cart" of the same product is clicked', async ( { - page, - } ) => { - let qty = 2; - while ( qty-- ) { - await goToShopPageAndAddProductToCart( page, productName ); + test( + 'should display no item in the cart', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await page.goto( '/cart/' ); + await expect( + page.getByText( 'Your cart is currently empty.' ) + ).toBeVisible(); } + ); - await page.goto( '/cart/' ); - await expect( page.locator( 'input.qty' ) ).toHaveValue( '2' ); - } ); + test( + 'should add the product to the cart from the shop page', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await goToShopPageAndAddProductToCart( page, productName ); - test( 'should update quantity when updated via quantity input', async ( { - page, - } ) => { - await goToShopPageAndAddProductToCart( page, productName ); + await page.goto( '/cart/' ); + await expect( page.locator( 'td.product-name' ) ).toContainText( + productName + ); + } + ); - await page.goto( '/cart/' ); - await page.locator( 'input.qty' ).fill( '2' ); - await page.locator( 'text=Update cart' ).click(); + test( + 'should increase item quantity when "Add to cart" of the same product is clicked', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + let qty = 2; + while ( qty-- ) { + await goToShopPageAndAddProductToCart( page, productName ); + } - await expect( page.locator( '.order-total .amount' ) ).toContainText( - `$${ twoProductPrice }` - ); - } ); + await page.goto( '/cart/' ); + await expect( page.locator( 'input.qty' ) ).toHaveValue( '2' ); + } + ); - test( 'should remove the item from the cart when remove is clicked', async ( { - page, - } ) => { - await goToShopPageAndAddProductToCart( page, productName ); - await page.goto( '/cart/' ); + test( + 'should update quantity when updated via quantity input', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await goToShopPageAndAddProductToCart( page, productName ); - // make sure that the product is in the cart - await expect( page.locator( '.order-total .amount' ) ).toContainText( - `$${ productPrice }` - ); + await page.goto( '/cart/' ); + await page.locator( 'input.qty' ).fill( '2' ); + await page.locator( 'text=Update cart' ).click(); - await page.locator( 'a.remove' ).click(); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( `$${ twoProductPrice }` ); + } + ); - await expect( - page.getByText( `“${ productName }” removed` ) - ).toBeVisible(); - await expect( - page.getByText( 'Your cart is currently empty' ) - ).toBeVisible(); - } ); + test( + 'should remove the item from the cart when remove is clicked', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await goToShopPageAndAddProductToCart( page, productName ); + await page.goto( '/cart/' ); - test( 'should update subtotal in cart totals when adding product to the cart', async ( { - page, - } ) => { - await goToShopPageAndAddProductToCart( page, productName ); + // make sure that the product is in the cart + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( `$${ productPrice }` ); - await page.goto( '/cart/' ); - await expect( page.locator( '.cart-subtotal .amount' ) ).toContainText( - `$${ productPrice }` - ); + await page.locator( 'a.remove' ).click(); - await page.locator( 'input.qty' ).fill( '2' ); - await page.locator( 'text=Update cart' ).click(); + await expect( + page.getByText( `“${ productName }” removed` ) + ).toBeVisible(); + await expect( + page.getByText( 'Your cart is currently empty' ) + ).toBeVisible(); + } + ); - await expect( page.locator( '.order-total .amount' ) ).toContainText( - `$${ twoProductPrice }` - ); - } ); + test( + 'should update subtotal in cart totals when adding product to the cart', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await goToShopPageAndAddProductToCart( page, productName ); - test( 'should go to the checkout page when "Proceed to Checkout" is clicked', async ( { - page, - } ) => { - await goToShopPageAndAddProductToCart( page, productName ); + await page.goto( '/cart/' ); + await expect( + page.locator( '.cart-subtotal .amount' ) + ).toContainText( `$${ productPrice }` ); - await page.goto( '/cart/' ); + await page.locator( 'input.qty' ).fill( '2' ); + await page.locator( 'text=Update cart' ).click(); - await page.locator( '.checkout-button' ).click(); + await expect( + page.locator( '.order-total .amount' ) + ).toContainText( `$${ twoProductPrice }` ); + } + ); - await expect( page.locator( '#order_review' ) ).toBeVisible(); - } ); + test( + 'should go to the checkout page when "Proceed to Checkout" is clicked', + { tag: [ '@could-be-unit-test' ] }, + async ( { page } ) => { + await goToShopPageAndAddProductToCart( page, productName ); + + await page.goto( '/cart/' ); + + await page.locator( '.checkout-button' ).click(); + + await expect( page.locator( '#order_review' ) ).toBeVisible(); + } + ); test( 'can manage cross-sell products and maximum item quantity', async ( { page, diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/launch-your-store.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/launch-your-store.spec.js index 0953328ce3a..5f85238a598 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/launch-your-store.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/launch-your-store.spec.js @@ -72,51 +72,43 @@ async function runComingSoonTests( themeContext = '' ) { } ); } -test.describe( - 'Launch Your Store front end - logged out', - { tag: [ '@payments', '@services' ] }, - () => { - test.afterAll( async ( { baseURL } ) => { - try { - await setOption( - request, - baseURL, - 'woocommerce_coming_soon', - 'no' - ); - } catch ( error ) { - console.log( error ); - } - } ); - - test.describe( 'Block Theme (Twenty Twenty Four)', () => { - test.beforeAll( async () => { - await activateTheme( 'twentytwentyfour' ); - } ); - - test.afterAll( async () => { - // Reset theme to the default. - await activateTheme( DEFAULT_THEME ); - } ); - - runComingSoonTests( test.step, test.use ); - } ); - - test.describe( 'Classic Theme (Storefront)', () => { - test.beforeAll( async () => { - await activateTheme( 'storefront' ); - } ); - - test.afterAll( async () => { - // Reset theme to the default. - await activateTheme( DEFAULT_THEME ); - } ); - - runComingSoonTests( - test.step, - test.use, - 'Classic Theme (Storefront)' +test.describe( 'Launch Your Store front end - logged out', () => { + test.afterAll( async ( { baseURL } ) => { + try { + await setOption( + request, + baseURL, + 'woocommerce_coming_soon', + 'no' ); + } catch ( error ) { + console.log( error ); + } + } ); + + test.describe( 'Block Theme (Twenty Twenty Four)', () => { + test.beforeAll( async () => { + await activateTheme( 'twentytwentyfour' ); } ); - } -); + + test.afterAll( async () => { + // Reset theme to the default. + await activateTheme( DEFAULT_THEME ); + } ); + + runComingSoonTests( test.step, test.use ); + } ); + + test.describe( 'Classic Theme (Storefront)', () => { + test.beforeAll( async () => { + await activateTheme( 'storefront' ); + } ); + + test.afterAll( async () => { + // Reset theme to the default. + await activateTheme( DEFAULT_THEME ); + } ); + + runComingSoonTests( test.step, test.use, 'Classic Theme (Storefront)' ); + } ); +} ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/shop-title-after-deletion.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/shop-title-after-deletion.spec.js index d967cff9d13..5c361b1ed50 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/shop-title-after-deletion.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/shop-title-after-deletion.spec.js @@ -3,7 +3,7 @@ const { test, expect } = require( '@playwright/test' ); // test case for bug https://github.com/woocommerce/woocommerce/pull/46429 test.describe( 'Check the title of the shop page after the page has been deleted', - { tag: [ '@payments', '@services' ] }, + { tag: [ '@payments', '@services', '@could-be-unit-test' ] }, () => { test.use( { storageState: process.env.ADMINSTATE } ); test.beforeEach( async ( { page } ) => { diff --git a/plugins/woocommerce/tests/e2e-pw/tests/shopper/wordpress-post.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/shopper/wordpress-post.spec.js index 6a1baa7c95d..fd6f46e0497 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/shopper/wordpress-post.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/shopper/wordpress-post.spec.js @@ -6,7 +6,7 @@ const test = baseTest.extend( { test( 'logged-in customer can comment on a post', - { tag: [ '@gutenberg', '@payments', '@services' ] }, + { tag: [ '@non-critical' ] }, async ( { page } ) => { await page.goto( 'hello-world/' ); await expect( From 8b35b0785c761bda0b90188ade462c83af5b3643 Mon Sep 17 00:00:00 2001 From: Sam Najian Date: Mon, 2 Sep 2024 14:23:52 +0200 Subject: [PATCH 175/185] Update woocommerce shipping promo banner [wc-shipping-188] (#50970) * Make sure the WC Shipping slug is used for installation * Make sure the check to show banner metabox work for HPOS as well * Make ShippingLabelBannerDisplayRules::order_has_shippable_products work with HPOS as well * Remove Jetpack plugin specific checks in ShippingLabelBannerDisplayRules * Use correct variable names for dotcom connection * Fix comments * Remove depenency on WCS&T for showing WC Shipping promo banner * Remove WC Tax and WC Shipping from incompatible plugins * Vary action button label if WCS&T is already installed * Inject config and render label purchase app after activation * Open the purchase modal after adding it to DOM * Render Shipment tracking metabox * Use a different headline when WCS&T is already installed * Fix UX when a none-compatible WCS&T is already active * Fix CSS linting issues * Fix Jslint issues * Improve around usage of localized variables * Fix and update JS tests * Address phpcs issues * Delete metaboxes of compatible WCS&T * Remove redundant variable assignment * Remove css and js of WCS&T if a compatible version is installed * Fix failing legacy PHPUnit tests * Only open the new label purchase modal if WCS&T is not active * Remove redundant code around TOS acceptance for showing the banner * Remove redundant test for Jetpack version checking * Make sure target passed to MutationObserver.observe is available * Add changelog file * Add openWcsModal to component's prototype * Add more js unit tests * Address PHP notice * Remove redundant variable assignments * Rename wcsPluginSlug to more clear wcShippingPluginSlug * Add a link to plugins page if incompatible WCS&T is already installed * Remove unused function parameters * Fix API resource path * Handle a case where none compatible version of WCShipping is installed --- .../shipping-banner/index.js | 384 ++++++++++-------- .../shipping-banner/test/index.js | 290 +++++++++---- .../print-shipping-label-banner/style.scss | 10 + .../print-shipping-label-banner/wcs-api.js | 12 +- ...date-woocommerce-shipping-promo-banner-188 | 4 + .../Internal/Admin/ShippingLabelBanner.php | 68 ++-- .../Admin/ShippingLabelBannerDisplayRules.php | 103 +---- ...ts-shipping-label-banner-display-rules.php | 86 +--- 8 files changed, 514 insertions(+), 443 deletions(-) create mode 100644 plugins/woocommerce/changelog/update-woocommerce-shipping-promo-banner-188 diff --git a/plugins/woocommerce-admin/client/wp-admin-scripts/print-shipping-label-banner/shipping-banner/index.js b/plugins/woocommerce-admin/client/wp-admin-scripts/print-shipping-label-banner/shipping-banner/index.js index 4a41285e9cd..1a29de7cc3e 100644 --- a/plugins/woocommerce-admin/client/wp-admin-scripts/print-shipping-label-banner/shipping-banner/index.js +++ b/plugins/woocommerce-admin/client/wp-admin-scripts/print-shipping-label-banner/shipping-banner/index.js @@ -1,17 +1,17 @@ /** * External dependencies */ -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { Button, ExternalLink } from '@wordpress/components'; import { compose } from '@wordpress/compose'; import interpolateComponents from '@automattic/interpolate-components'; import PropTypes from 'prop-types'; -import { get, isArray } from 'lodash'; import { PLUGINS_STORE_NAME } from '@woocommerce/data'; import { withDispatch, withSelect } from '@wordpress/data'; import { recordEvent } from '@woocommerce/tracks'; -import { getSetting } from '@woocommerce/settings'; +import { getSetting, getAdminLink } from '@woocommerce/settings'; +import { Link } from '@woocommerce/components'; /** * Internal dependencies @@ -19,29 +19,28 @@ import { getSetting } from '@woocommerce/settings'; import '../style.scss'; import DismissModal from '../dismiss-modal'; import SetupNotice, { setupErrorTypes } from '../setup-notice'; -import { getWcsAssets, acceptWcsTos } from '../wcs-api'; +import { + getWcsAssets, + acceptWcsTos, + getWcsLabelPurchaseConfigs, +} from '../wcs-api'; const wcAssetUrl = getSetting( 'wcAssetUrl', '' ); -const wcsPluginSlug = 'woocommerce-services'; +const wcShippingPluginSlug = 'woocommerce-shipping'; +const wcstPluginSlug = 'woocommerce-services'; export class ShippingBanner extends Component { constructor( props ) { super( props ); - const orderId = new URL( window.location.href ).searchParams.get( - 'post' - ); - this.state = { showShippingBanner: true, isDismissModalOpen: false, setupErrorReason: setupErrorTypes.SETUP, - orderId: parseInt( orderId, 10 ), wcsAssetsLoaded: false, wcsAssetsLoading: false, wcsSetupError: false, isShippingLabelButtonBusy: false, - installText: this.getInstallText(), isWcsModalOpen: false, }; } @@ -76,8 +75,8 @@ export class ShippingBanner extends Component { const { activePlugins } = this.props; this.setState( { isShippingLabelButtonBusy: true } ); this.trackElementClicked( 'shipping_banner_create_label' ); - if ( ! activePlugins.includes( wcsPluginSlug ) ) { - this.installAndActivatePlugins( wcsPluginSlug ); + if ( ! activePlugins.includes( wcShippingPluginSlug ) ) { + this.installAndActivatePlugins( wcShippingPluginSlug ); } else { this.acceptTosAndGetWCSAssets(); } @@ -85,7 +84,14 @@ export class ShippingBanner extends Component { async installAndActivatePlugins( pluginSlug ) { // Avoid double activating. - const { installPlugins, activatePlugins, isRequesting } = this.props; + const { + installPlugins, + activatePlugins, + isRequesting, + activePlugins, + isWcstCompatible, + isIncompatibleWCShippingInstalled, + } = this.props; if ( isRequesting ) { return false; } @@ -107,7 +113,25 @@ export class ShippingBanner extends Component { return; } - this.acceptTosAndGetWCSAssets(); + /** + * If a incompatible version of the WooCommerce Shipping plugin is installed, the necessary endpoints + * are not available, so we need to reload the page to ensure to make the plugin usable. + */ + if ( isIncompatibleWCShippingInstalled ) { + window.location.reload( true ); + return; + } + + if ( + ! activePlugins.includes( wcShippingPluginSlug ) && + isWcstCompatible + ) { + this.acceptTosAndGetWCSAssets(); + } else { + this.setState( { + showShippingBanner: false, + } ); + } } woocommerceServiceLinkClicked = () => { @@ -120,7 +144,7 @@ export class ShippingBanner extends Component { banner_name: 'wcadmin_install_wcs_prompt', jetpack_installed: activePlugins.includes( 'jetpack' ), jetpack_connected: isJetpackConnected, - wcs_installed: activePlugins.includes( wcsPluginSlug ), + wcs_installed: activePlugins.includes( wcShippingPluginSlug ), ...customProps, } ); }; @@ -135,16 +159,21 @@ export class ShippingBanner extends Component { } ); }; - acceptTosAndGetWCSAssets() { + acceptTosAndGetWCSAssets = () => { return acceptWcsTos() + .then( () => getWcsLabelPurchaseConfigs( this.props.orderId ) ) + .then( ( configs ) => { + window.WCShipping_Config = configs.config; + return configs; + } ) .then( () => getWcsAssets() ) .then( ( wcsAssets ) => this.loadWcsAssets( wcsAssets ) ) - .catch( () => this.setState( { wcsSetupError: true } ) ); - } + .catch( () => { + this.setState( { wcsSetupError: true } ); + } ); + }; generateMetaBoxHtml( nodeId, title, args ) { - const argsJsonString = JSON.stringify( args ).replace( /"/g, '"' ); // JS has no native html_entities so we just replace. - const togglePanelText = __( 'Toggle panel:', 'woocommerce' ); return ` @@ -159,8 +188,7 @@ export class ShippingBanner extends Component {
        -
        -
        +
        `; @@ -174,27 +202,24 @@ export class ShippingBanner extends Component { this.setState( { wcsAssetsLoading: true } ); - const jsPath = assets.wc_connect_admin_script; - const stylePath = assets.wc_connect_admin_style; + const labelPurchaseMetaboxId = 'woocommerce-order-label'; + const shipmentTrackingMetaboxId = 'woocommerce-order-shipment-tracking'; + const jsPath = assets.wcshipping_create_label_script; + const stylePath = assets.wcshipping_create_label_style; - if ( undefined === window.wcsPluginData ) { - const assetPath = jsPath.substring( - 0, - jsPath.lastIndexOf( '/' ) + 1 - ); - window.wcsPluginData = { assetPath }; - } + const shipmentTrackingJsPath = + assets.wcshipping_shipment_tracking_script; + const shipmentTrackingStylePath = + assets.wcshipping_shipment_tracking_style; - const { orderId } = this.state; - const { itemsCount } = this.props; + const { activePlugins } = this.props; + document.getElementById( labelPurchaseMetaboxId )?.remove(); const shippingLabelContainerHtml = this.generateMetaBoxHtml( - 'woocommerce-order-label', + labelPurchaseMetaboxId, __( 'Shipping Label', 'woocommerce' ), { - order: { id: orderId }, context: 'shipping_label', - items: itemsCount, } ); // Insert shipping label metabox just above main order details box. @@ -202,13 +227,12 @@ export class ShippingBanner extends Component { .getElementById( 'woocommerce-order-data' ) .insertAdjacentHTML( 'beforebegin', shippingLabelContainerHtml ); + document.getElementById( shipmentTrackingMetaboxId )?.remove(); const shipmentTrackingHtml = this.generateMetaBoxHtml( - 'woocommerce-order-shipment-tracking', + shipmentTrackingMetaboxId, __( 'Shipment Tracking', 'woocommerce' ), { - order: { id: orderId }, context: 'shipment_tracking', - items: itemsCount, } ); // Insert tracking metabox in the side after the order actions. @@ -224,6 +248,13 @@ export class ShippingBanner extends Component { window.jQuery( '#woocommerce-order-label' ).hide(); } + document + .querySelectorAll( 'script[src*="/woocommerce-services/"]' ) + .forEach( ( node ) => node.remove?.() ); + document + .querySelectorAll( 'link[href*="/woocommerce-services/"]' ) + .forEach( ( node ) => node.remove?.() ); + Promise.all( [ new Promise( ( resolve, reject ) => { const script = document.createElement( 'script' ); @@ -233,9 +264,16 @@ export class ShippingBanner extends Component { script.onerror = reject; document.body.appendChild( script ); } ), + new Promise( ( resolve, reject ) => { + const script = document.createElement( 'script' ); + script.src = shipmentTrackingJsPath; + script.async = true; + script.onload = resolve; + script.onerror = reject; + document.body.appendChild( script ); + } ), new Promise( ( resolve, reject ) => { if ( stylePath !== '' ) { - const head = document.getElementsByTagName( 'head' )[ 0 ]; const link = document.createElement( 'link' ); link.rel = 'stylesheet'; link.type = 'text/css'; @@ -243,7 +281,23 @@ export class ShippingBanner extends Component { link.media = 'all'; link.onload = resolve; link.onerror = reject; - head.appendChild( link ); + link.id = 'wcshipping-injected-styles'; + document.head.appendChild( link ); + } else { + resolve(); + } + } ), + new Promise( ( resolve, reject ) => { + if ( shipmentTrackingStylePath !== '' ) { + const link = document.createElement( 'link' ); + link.rel = 'stylesheet'; + link.type = 'text/css'; + link.href = shipmentTrackingStylePath; + link.media = 'all'; + link.onload = resolve; + link.onerror = reject; + link.id = 'wcshipping-injected-styles'; + document.head.appendChild( link ); } else { resolve(); } @@ -254,133 +308,61 @@ export class ShippingBanner extends Component { wcsAssetsLoading: false, isShippingLabelButtonBusy: false, } ); - this.openWcsModal(); + + // Reshow the shipping label metabox. + if ( window.jQuery ) { + window.jQuery( '#woocommerce-order-label' ).show(); + } + + document.getElementById( + 'woocommerce-admin-print-label' + ).style.display = 'none'; + + /** + * We'll only get to this point if either WCS&T is not active or is active but compatible with WooCommerce Shipping + * so once we check if the WCS&T is not active, we can open the label purchase modal immediately. + */ + if ( ! activePlugins.includes( wcstPluginSlug ) ) { + this.openWcsModal(); + } } ); } - getInstallText = () => { - const { activePlugins } = this.props; - if ( activePlugins.includes( wcsPluginSlug ) ) { - // If WCS is active, then the only remaining step is to agree to the ToS. - return __( - 'You\'ve already installed WooCommerce Shipping. By clicking "Create shipping label", you agree to its {{tosLink}}Terms of Service{{/tosLink}}.', - 'woocommerce' - ); - } - return __( - 'By clicking "Create shipping label", {{wcsLink}}WooCommerce Shipping{{/wcsLink}} will be installed and you agree to its {{tosLink}}Terms of Service{{/tosLink}}.', - 'woocommerce' - ); - }; - openWcsModal() { - if ( window.wcsGetAppStoreAsync ) { - window - .wcsGetAppStoreAsync( 'wc-connect-create-shipping-label' ) - .then( ( wcsStore ) => { - const state = wcsStore.getState(); - const { orderId } = this.state; - const siteId = state.ui.selectedSiteId; + // Since the button is dynamically added, we need to wait for it to become selectable and then click it. - const wcsStoreUnsubscribe = wcsStore.subscribe( () => { - const latestState = wcsStore.getState(); + const buttonSelector = + '#woocommerce-shipping-shipping-label-shipping_label button'; + if ( window.MutationObserver ) { + const observer = new window.MutationObserver( + ( mutationsList, observing ) => { + const button = document.querySelector( buttonSelector ); + if ( button ) { + button.click(); + observing.disconnect(); + } + } + ); - const shippingLabelState = get( - latestState, - [ - 'extensions', - 'woocommerce', - 'woocommerceServices', - siteId, - 'shippingLabel', - orderId, - ], - null - ); - - const labelSettingsState = get( - latestState, - [ - 'extensions', - 'woocommerce', - 'woocommerceServices', - siteId, - 'labelSettings', - ], - null - ); - - const packageState = get( - latestState, - [ - 'extensions', - 'woocommerce', - 'woocommerceServices', - siteId, - 'packages', - ], - null - ); - - const locationsState = get( latestState, [ - 'extensions', - 'woocommerce', - 'sites', - siteId, - 'data', - 'locations', - ] ); - - if ( - shippingLabelState && - labelSettingsState && - labelSettingsState.meta && - packageState && - locationsState - ) { - if ( - shippingLabelState.loaded && - labelSettingsState.meta.isLoaded && - packageState.isLoaded && - isArray( locationsState ) && - ! this.state.isWcsModalOpen - ) { - if ( window.jQuery ) { - this.setState( { isWcsModalOpen: true } ); - window - .jQuery( - '.shipping-label__new-label-button' - ) - .click(); - } - wcsStore.dispatch( { - type: 'NOTICE_CREATE', - notice: { - duration: 10000, - status: 'is-success', - text: __( - 'Plugin installed and activated', - 'woocommerce' - ), - }, - } ); - } else if ( - shippingLabelState.showPurchaseDialog - ) { - wcsStoreUnsubscribe(); - if ( window.jQuery ) { - window - .jQuery( '#woocommerce-order-label' ) - .show(); - } - } - } - } ); - - document.getElementById( - 'woocommerce-admin-print-label' - ).style.display = 'none'; - } ); + observer.observe( + document.getElementById( + 'woocommerce-shipping-shipping-label-shipping_label' + ) ?? + document.getElementById( 'wpbody-content' ) ?? + document.body, + { + childList: true, + subtree: true, + } + ); + } else { + const interval = setInterval( () => { + const targetElement = document.querySelector( buttonSelector ); + if ( targetElement ) { + targetElement.click(); + clearInterval( interval ); + } + }, 300 ); } } @@ -390,10 +372,40 @@ export class ShippingBanner extends Component { showShippingBanner, isShippingLabelButtonBusy, } = this.state; + const { isWcstCompatible } = this.props; + if ( ! showShippingBanner && ! isWcstCompatible ) { + document + .getElementById( 'woocommerce-admin-print-label' ) + .classList.add( 'error' ); + + return ( +

        + + { interpolateComponents( { + mixedString: __( + 'Please {{pluginPageLink}}update{{/pluginPageLink}} the WooCommerce Shipping & Tax plugin to the latest version to ensure compatibility with WooCommerce Shipping.', + 'woocommerce' + ), + components: { + pluginPageLink: ( + + ), + }, + } ) } + +

        + ); + } + if ( ! showShippingBanner ) { return null; } + const { actionButtonLabel, headline } = this.props; return (
        @@ -403,15 +415,17 @@ export class ShippingBanner extends Component { alt={ __( 'Shipping ', 'woocommerce' ) } />
        -

        - { __( - 'Print discounted shipping labels with a click.', - 'woocommerce' - ) } -

        +

        { headline }

        { interpolateComponents( { - mixedString: this.state.installText, + mixedString: sprintf( + // translators: %s is the action button label. + __( + 'By clicking "%s", {{wcsLink}}WooCommerce Shipping{{/wcsLink}} will be installed and you agree to its {{tosLink}}Terms of Service{{/tosLink}}.', + 'woocommerce' + ), + actionButtonLabel + ), components: { tosLink: ( - { __( 'Create shipping label', 'woocommerce' ) } + { actionButtonLabel }