Add TypeScript support and convert cart data store to TypeScript (https://github.com/woocommerce/woocommerce-blocks/pull/3768)

* add typescript support

* Add type declarations for Cart and CartResponse interfaces

* make sure we’re resolving .ts files as well as .js files on imports

* add more types

* type the cart data store

* Apply suggestions from code review (implement .tsx in configs)

Co-authored-by: Jon Surrell <jon.surrell@automattic.com>

* remove global fetchMock declaration and directly import where used.

* rename type

* remove named action types and just infer by returning action creator values as const

* use interface instead of type

* rename

* renames

* create CartAction type as union of action creator returned types and implement in reducer

* remove unused imports

* refresh package-lock after rebase

* Add base TS config that projects will inherit from

* Add tsconfig for assets/js/data project

* Ignore TS error on cart store registration

We will address this in cooldown when we have time to investigate further

* Add tsc to build step to catch TypeScript errors

* add a separate command for tsc and tweak build command to use

* restore checkJs and allowJs values in config and remove ts check from build command

* Add ts:check-all command

* Add TypeScript checking workflows

* Change triggers for TypeScript workflow

* Use npm ci instead of npm install

* Remove ts:check-all from TypeScript workflow

* Remove TS Check GitHub workflow

* Remove type-defs dir from TS include, and remove ts:check-all script

We no longer need the ts:check-all script because ts:check will do this for us, the old ts:check did nothing and did not work.

* fix coupon loading issues

* include .ts files only from type-defs folder

Co-authored-by: Jon Surrell <jon.surrell@automattic.com>
Co-authored-by: Thomas Roberts <thomas.roberts@automattic.com>
This commit is contained in:
Darren Ethier 2021-02-23 20:36:24 -05:00 committed by GitHub
parent 549afc1065
commit af99c16931
25 changed files with 1475 additions and 379 deletions

View File

@ -52,6 +52,7 @@ module.exports = {
'import/resolver': {
node: {},
webpack: {},
typescript: {},
},
},
rules: {
@ -67,5 +68,20 @@ module.exports = {
'you-dont-need-lodash-underscore/omit': 'off',
},
},
{
files: [ '*.ts', '*.tsx' ],
parser: '@typescript-eslint/parser',
extends: [
'plugin:@woocommerce/eslint-plugin/recommended',
'plugin:you-dont-need-lodash-underscore/compatible',
'plugin:@typescript-eslint/recommended',
],
rules: {
'@typescript-eslint/no-explicit-any': 'error',
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': [ 'error' ],
'jsdoc/require-param': 'off',
},
},
],
};

View File

@ -11,6 +11,7 @@ import {
__experimentalDeRegisterPaymentMethod,
__experimentalDeRegisterExpressPaymentMethod,
} from '@woocommerce/blocks-registry';
import { default as fetchMock } from 'jest-fetch-mock';
/**
* Internal dependencies
@ -129,6 +130,7 @@ describe( 'Testing Payment Method Data Context Provider', () => {
if ( req.url.match( /wc\/store\/cart/ ) ) {
return Promise.resolve( JSON.stringify( previewCart ) );
}
return Promise.resolve( '' );
} );
// need to clear the store resolution state between tests.
await dispatch( storeKey ).invalidateResolutionForStore();

View File

@ -5,6 +5,8 @@ import { render, screen, waitFor } from '@testing-library/react';
import { previewCart } from '@woocommerce/resource-previews';
import { dispatch } from '@wordpress/data';
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
import { default as fetchMock } from 'jest-fetch-mock';
/**
* Internal dependencies
*/
@ -17,6 +19,7 @@ describe( 'Testing cart', () => {
if ( req.url.match( /wc\/store\/cart/ ) ) {
return Promise.resolve( JSON.stringify( previewCart ) );
}
return Promise.resolve( '' );
} );
// need to clear the store resolution state between tests.
await dispatch( storeKey ).invalidateResolutionForStore();
@ -51,6 +54,7 @@ describe( 'Testing cart', () => {
JSON.stringify( defaultCartState.cartData )
);
}
return Promise.resolve( '' );
} );
render(
<CartBlock

View File

@ -9,4 +9,4 @@ export const ACTION_TYPES = {
RECEIVE_REMOVED_ITEM: 'RECEIVE_REMOVED_ITEM',
UPDATING_CUSTOMER_DATA: 'UPDATING_CUSTOMER_DATA',
UPDATING_SELECTED_SHIPPING_RATE: 'UPDATING_SELECTED_SHIPPING_RATE',
};
} as const;

View File

@ -2,6 +2,14 @@
* External dependencies
*/
import { select } from '@wordpress/data-controls';
import type {
Cart,
CartResponse,
CartResponseItem,
CartBillingAddress,
CartShippingAddress,
} from '@woocommerce/types';
import { camelCase, mapKeys } from 'lodash';
/**
* Internal dependencies
@ -9,6 +17,7 @@ import { select } from '@wordpress/data-controls';
import { ACTION_TYPES as types } from './action-types';
import { STORE_KEY as CART_STORE_KEY } from './constants';
import { apiFetchWithHeaders } from '../shared-controls';
import type { ResponseError } from '../types';
/**
* Returns an action object used in updating the store with the provided items
@ -16,142 +25,143 @@ import { apiFetchWithHeaders } from '../shared-controls';
*
* This is a generic response action.
*
* @param {Object} [response={}] An object containing the response from the
* request.
* @return {Object} Object for action.
* @param {CartResponse} response
*/
export function receiveCart( response = {} ) {
export function receiveCart( response: CartResponse ) {
const cart = ( mapKeys( response, ( _, key ) =>
camelCase( key )
) as unknown ) as Cart;
return {
type: types.RECEIVE_CART,
response,
};
response: cart,
} as const;
}
/**
* Returns an action object used for receiving customer facing errors from the
* API.
* Returns an action object used for receiving customer facing errors from the API.
*
* @param {Object} [error={}] An error object containing the error message
* and response code.
* @param {boolean} [replace=true] Should existing errors be replaced, or should
* the error be appended.
* @return {Object} Object for action.
* @param {ResponseError|null} [error=null] An error object containing the error
* message and response code.
* @param {boolean} [replace=true] Should existing errors be replaced,
* or should the error be appended.
*/
export function receiveError( error = {}, replace = true ) {
export function receiveError(
error: ResponseError | null = null,
replace = true
) {
return {
type: replace ? types.REPLACE_ERRORS : types.RECEIVE_ERROR,
error,
};
} as const;
}
/**
* Returns an action object used to track when a coupon is applying.
*
* @param {string} [couponCode] Coupon being added.
* @return {Object} Object for action.
* @param {string} [couponCode] Coupon being added.
*/
export function receiveApplyingCoupon( couponCode ) {
export function receiveApplyingCoupon( couponCode: string ) {
return {
type: types.APPLYING_COUPON,
couponCode,
};
} as const;
}
/**
* Returns an action object used to track when a coupon is removing.
*
* @param {string} [couponCode] Coupon being removed.
* @return {Object} Object for action.
* @param {string} [couponCode] Coupon being removed..
*/
export function receiveRemovingCoupon( couponCode ) {
export function receiveRemovingCoupon( couponCode: string ) {
return {
type: types.REMOVING_COUPON,
couponCode,
};
} as const;
}
/**
* Returns an action object for updating a single cart item in the store.
*
* @param {Object} [response={}] A cart item API response.
* @return {Object} Object for action.
* @param {CartResponseItem} [response=null] A cart item API response.
*/
export function receiveCartItem( response = {} ) {
export function receiveCartItem( response: CartResponseItem | null = null ) {
return {
type: types.RECEIVE_CART_ITEM,
cartItem: response,
};
} as const;
}
/**
* Returns an action object to indicate if the specified cart item
* quantity is being updated.
* Returns an action object to indicate if the specified cart item quantity is
* being updated.
*
* @param {string} cartItemKey Cart item being updated.
* @param {boolean} isPendingQuantity Flag for update state; true if API request
* is pending.
* @return {Object} Object for action.
* @param {string} cartItemKey Cart item being updated.
* @param {boolean} [isPendingQuantity=true] Flag for update state; true if API
* request is pending.
*/
export function itemIsPendingQuantity( cartItemKey, isPendingQuantity = true ) {
export function itemIsPendingQuantity(
cartItemKey: string,
isPendingQuantity = true
) {
return {
type: types.ITEM_PENDING_QUANTITY,
cartItemKey,
isPendingQuantity,
};
} as const;
}
/**
* Returns an action object to remove a cart item from the store.
*
* @param {string} cartItemKey Cart item to remove.
* @param {boolean} isPendingDelete Flag for update state; true if API request
* is pending.
* @return {Object} Object for action.
* @param {string} cartItemKey Cart item to remove.
* @param {boolean} [isPendingDelete=true] Flag for update state; true if API
* request is pending.
*/
export function itemIsPendingDelete( cartItemKey, isPendingDelete = true ) {
export function itemIsPendingDelete(
cartItemKey: string,
isPendingDelete = true
) {
return {
type: types.RECEIVE_REMOVED_ITEM,
cartItemKey,
isPendingDelete,
};
} as const;
}
/**
* Returns an action object used to track when customer data is being updated (billing and/or shipping).
*
* @param {boolean} isResolving if we're updating customer data or not.
* @return {Object} Object for action.
* Returns an action object used to track when customer data is being updated
* (billing and/or shipping).
*/
export function updatingCustomerData( isResolving ) {
export function updatingCustomerData( isResolving: boolean ) {
return {
type: types.UPDATING_CUSTOMER_DATA,
isResolving,
};
} as const;
}
/**
* Returns an action object used to track whether the shipping rate is being
* selected or not.
*
* @param {boolean} isResolving True if shipping rate is being selected.
*
* @return {Object} Action object.
* @param {boolean} isResolving True if shipping rate is being selected.
*/
export function shippingRatesBeingSelected( isResolving ) {
export function shippingRatesBeingSelected( isResolving: boolean ) {
return {
type: types.UPDATING_SELECTED_SHIPPING_RATE,
isResolving,
};
} as const;
}
/**
* Applies a coupon code and either invalidates caches, or receives an error if
* the coupon cannot be applied.
*
* @throws Will throw an error if there is an API problem.
* @param {string} couponCode The coupon code to apply to the cart.
* @param {string} couponCode The coupon code to apply to the cart.
* @throws Will throw an error if there is an API problem.
*/
export function* applyCoupon( couponCode ) {
export function* applyCoupon(
couponCode: string
): Generator< unknown, boolean, { response: CartResponse } > {
yield receiveApplyingCoupon( couponCode );
try {
@ -186,10 +196,12 @@ export function* applyCoupon( couponCode ) {
* Removes a coupon code and either invalidates caches, or receives an error if
* the coupon cannot be removed.
*
* @throws Will throw an error if there is an API problem.
* @param {string} couponCode The coupon code to remove from the cart.
* @param {string} couponCode The coupon code to remove from the cart.
* @throws Will throw an error if there is an API problem.
*/
export function* removeCoupon( couponCode ) {
export function* removeCoupon(
couponCode: string
): Generator< unknown, boolean, { response: CartResponse } > {
yield receiveRemovingCoupon( couponCode );
try {
@ -226,11 +238,14 @@ export function* removeCoupon( couponCode ) {
* - If successful, yields action to add item from store.
* - If error, yields action to store error.
*
* @throws Will throw an error if there is an API problem.
* @param {number} productId Product ID to add to cart.
* @param {number} quantity Number of product ID being added to cart.
* @param {number} productId Product ID to add to cart.
* @param {number} [quantity=1] Number of product ID being added to cart.
* @throws Will throw an error if there is an API problem.
*/
export function* addItemToCart( productId, quantity = 1 ) {
export function* addItemToCart(
productId: number,
quantity = 1
): Generator< unknown, void, { response: CartResponse } > {
try {
const { response } = yield apiFetchWithHeaders( {
path: `/wc/store/cart/add-item`,
@ -254,8 +269,6 @@ export function* addItemToCart( productId, quantity = 1 ) {
// Re-throw the error.
throw error;
}
return true;
}
/**
@ -267,7 +280,9 @@ export function* addItemToCart( productId, quantity = 1 ) {
*
* @param {string} cartItemKey Cart item being updated.
*/
export function* removeItemFromCart( cartItemKey ) {
export function* removeItemFromCart(
cartItemKey: string
): Generator< unknown, void, { response: CartResponse } > {
yield itemIsPendingDelete( cartItemKey );
try {
@ -296,9 +311,13 @@ export function* removeItemFromCart( cartItemKey ) {
* - If error, yields action to store error.
*
* @param {string} cartItemKey Cart item being updated.
* @param {number} quantity Specified (new) quantity.
* @param {number} quantity Specified (new) quantity.
*/
export function* changeCartItemQuantity( cartItemKey, quantity ) {
export function* changeCartItemQuantity(
cartItemKey: string,
quantity: number
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- unclear how to represent multiple different yields as type
): Generator< unknown, void, any > {
const cartItem = yield select( CART_STORE_KEY, 'getCartItem', cartItemKey );
yield itemIsPendingQuantity( cartItemKey );
@ -331,10 +350,14 @@ export function* changeCartItemQuantity( cartItemKey, quantity ) {
/**
* Selects a shipping rate.
*
* @param {string} rateId the id of the rate being selected.
* @param {number|string} [packageId] the key of the packages that we will select within.
* @param {string} rateId The id of the rate being selected.
* @param {number | string} [packageId] The key of the packages that we will
* select within.
*/
export function* selectShippingRate( rateId, packageId = 0 ) {
export function* selectShippingRate(
rateId: string,
packageId = 0
): Generator< unknown, boolean, { response: CartResponse } > {
try {
yield shippingRatesBeingSelected( true );
const { response } = yield apiFetchWithHeaders( {
@ -364,12 +387,23 @@ export function* selectShippingRate( rateId, packageId = 0 ) {
return true;
}
type BillingAddressShippingAddress = {
// eslint-disable-next-line camelcase
billing_address: CartBillingAddress;
// eslint-disable-next-line camelcase
shipping_address: CartShippingAddress;
};
/**
* Updates the shipping and/or billing address for the customer and returns an updated cart.
* Updates the shipping and/or billing address for the customer and returns an
* updated cart.
*
* @param {Object} customerData Address data to be updated; can contain both billing_address and shipping_address.
* @param {BillingAddressShippingAddress} customerData Address data to be updated; can contain both
* billing_address and shipping_address.
*/
export function* updateCustomerData( customerData ) {
export function* updateCustomerData(
customerData: BillingAddressShippingAddress
): Generator< unknown, boolean, { response: CartResponse } > {
yield updatingCustomerData( true );
try {
@ -397,3 +431,15 @@ export function* updateCustomerData( customerData ) {
yield updatingCustomerData( false );
return true;
}
export type CartAction = ReturnType<
| typeof receiveCart
| typeof receiveError
| typeof receiveApplyingCoupon
| typeof receiveRemovingCoupon
| typeof receiveCartItem
| typeof itemIsPendingQuantity
| typeof itemIsPendingDelete
| typeof updatingCustomerData
| typeof shippingRatesBeingSelected
>;

View File

@ -15,8 +15,12 @@ import reducer from './reducers';
import { controls } from '../shared-controls';
registerStore( STORE_KEY, {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- Can't figure out how to resolve this now
reducer,
actions,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- not sure how to resolve the type issues here.
controls: { ...dataControls, ...controls },
selectors,
resolvers,

View File

@ -1,26 +1,30 @@
/**
* External dependencies
*/
import { camelCase, mapKeys } from 'lodash';
import type { CartItem } from '@woocommerce/types';
/**
* Internal dependencies
*/
import { ACTION_TYPES as types } from './action-types';
import { defaultCartState } from '../default-states';
import { defaultCartState, CartState } from '../default-states';
import type { CartAction } from './actions';
/**
* Sub-reducer for cart items array.
*
* @param {Array} state cartData.items state slice.
* @param {Object} action Action object.
* @param {Array<CartItem>} state cartData.items state slice.
* @param {CartAction} action Action object.
*/
const cartItemsReducer = ( state = [], action ) => {
const cartItemsReducer = (
state: Array< CartItem > = [],
action: CartAction
) => {
switch ( action.type ) {
case types.RECEIVE_CART_ITEM:
// Replace specified cart element with the new data from server.
return state.map( ( cartItem ) => {
if ( cartItem.key === action.cartItem.key ) {
if ( cartItem.key === action.cartItem?.key ) {
return action.cartItem;
}
return cartItem;
@ -32,51 +36,62 @@ const cartItemsReducer = ( state = [], action ) => {
/**
* Reducer for receiving items related to the cart.
*
* @param {Object} state The current state in the store.
* @param {Object} action Action object.
* @param {CartState} state The current state in the store.
* @param {CartAction} action Action object.
*
* @return {Object} New or existing state.
* @return {CartState} New or existing state.
*/
const reducer = ( state = defaultCartState, action ) => {
const reducer = (
state: CartState = defaultCartState,
action: CartAction
): CartState => {
switch ( action.type ) {
case types.RECEIVE_ERROR:
state = {
...state,
errors: state.errors.concat( action.error ),
};
if ( action.error ) {
state = {
...state,
errors: state.errors.concat( action.error ),
};
}
break;
case types.REPLACE_ERRORS:
state = {
...state,
errors: [ action.error ],
};
if ( action.error ) {
state = {
...state,
errors: [ action.error ],
};
}
break;
case types.RECEIVE_CART:
state = {
...state,
errors: [],
cartData: mapKeys( action.response, ( _, key ) =>
camelCase( key )
),
};
if ( action.response ) {
state = {
...state,
errors: [],
cartData: action.response,
};
}
break;
case types.APPLYING_COUPON:
state = {
...state,
metaData: {
...state.metaData,
applyingCoupon: action.couponCode,
},
};
if ( action.couponCode || action.couponCode === '' ) {
state = {
...state,
metaData: {
...state.metaData,
applyingCoupon: action.couponCode,
},
};
}
break;
case types.REMOVING_COUPON:
state = {
...state,
metaData: {
...state.metaData,
removingCoupon: action.couponCode,
},
};
if ( action.couponCode || action.couponCode === '' ) {
state = {
...state,
metaData: {
...state.metaData,
removingCoupon: action.couponCode,
},
};
}
break;
case types.ITEM_PENDING_QUANTITY:
@ -85,7 +100,7 @@ const reducer = ( state = defaultCartState, action ) => {
const keysPendingQuantity = state.cartItemsPendingQuantity.filter(
( key ) => key !== action.cartItemKey
);
if ( action.isPendingQuantity ) {
if ( action.isPendingQuantity && action.cartItemKey ) {
keysPendingQuantity.push( action.cartItemKey );
}
state = {
@ -97,7 +112,7 @@ const reducer = ( state = defaultCartState, action ) => {
const keysPendingDelete = state.cartItemsPendingDelete.filter(
( key ) => key !== action.cartItemKey
);
if ( action.isPendingDelete ) {
if ( action.isPendingDelete && action.cartItemKey ) {
keysPendingDelete.push( action.cartItemKey );
}
state = {
@ -121,7 +136,7 @@ const reducer = ( state = defaultCartState, action ) => {
...state,
metaData: {
...state.metaData,
updatingCustomerData: action.isResolving,
updatingCustomerData: !! action.isResolving,
},
};
break;
@ -130,7 +145,7 @@ const reducer = ( state = defaultCartState, action ) => {
...state,
metaData: {
...state.metaData,
updatingSelectedRate: action.isResolving,
updatingSelectedRate: !! action.isResolving,
},
};
}

View File

@ -2,6 +2,7 @@
* External dependencies
*/
import { select, apiFetch } from '@wordpress/data-controls';
import { CartResponse, Cart } from '@woocommerce/types';
/**
* Internal dependencies
@ -12,7 +13,7 @@ import { STORE_KEY, CART_API_ERROR } from './constants';
/**
* Resolver for retrieving all cart data.
*/
export function* getCartData() {
export function* getCartData(): Generator< unknown, void, CartResponse > {
const cartData = yield apiFetch( {
path: '/wc/store/cart',
method: 'GET',
@ -30,6 +31,6 @@ export function* getCartData() {
/**
* Resolver for retrieving cart totals.
*/
export function* getCartTotals() {
export function* getCartTotals(): Generator< unknown, void, Cart > {
yield select( STORE_KEY, 'getCartData' );
}

View File

@ -1,164 +0,0 @@
/** @typedef { import('@woocommerce/type-defs/cart').CartData } CartData */
/** @typedef { import('@woocommerce/type-defs/cart').CartTotals } CartTotals */
/**
* Retrieves cart data from state.
*
* @param {Object} state The current state.
* @return {CartData} The data to return.
*/
export const getCartData = ( state ) => {
return state.cartData;
};
/**
* Retrieves cart totals from state.
*
* @param {Object} state The current state.
* @return {CartTotals} The data to return.
*/
export const getCartTotals = ( state ) => {
return (
state.cartData.totals || {
currency_code: '',
currency_symbol: '',
currency_minor_unit: 2,
currency_decimal_separator: '.',
currency_thousand_separator: ',',
currency_prefix: '',
currency_suffix: '',
total_items: '0',
total_items_tax: '0',
total_fees: '0',
total_fees_tax: '0',
total_discount: '0',
total_discount_tax: '0',
total_shipping: '0',
total_shipping_tax: '0',
total_price: '0',
total_tax: '0',
tax_lines: [],
}
);
};
/**
* Retrieves cart meta from state.
*
* @param {Object} state The current state.
* @return {Object} The data to return.
*/
export const getCartMeta = ( state ) => {
return (
state.metaData || {
applyingCoupon: '',
removingCoupon: '',
}
);
};
/**
* Retrieves cart errors from state.
*
* @param {Object} state The current state.
* @return {Array} Array of errors.
*/
export const getCartErrors = ( state ) => {
return state.errors || [];
};
/**
* Returns true if any coupon is being applied.
*
* @param {Object} state The current state.
* @return {boolean} True if a coupon is being applied.
*/
export const isApplyingCoupon = ( state ) => {
return !! state.metaData.applyingCoupon;
};
/**
* Retrieves the coupon code currently being applied.
*
* @param {Object} state The current state.
* @return {string} The data to return.
*/
export const getCouponBeingApplied = ( state ) => {
return state.metaData.applyingCoupon || '';
};
/**
* Returns true if any coupon is being removed.
*
* @param {Object} state The current state.
* @return {boolean} True if a coupon is being removed.
*/
export const isRemovingCoupon = ( state ) => {
return !! state.metaData.removingCoupon;
};
/**
* Retrieves the coupon code currently being removed.
*
* @param {Object} state The current state.
* @return {string} The data to return.
*/
export const getCouponBeingRemoved = ( state ) => {
return state.metaData.removingCoupon || '';
};
/**
* Returns cart item matching specified key.
*
* @param {Object} state The current state.
* @param {string} cartItemKey Key for a cart item.
* @return {Object} Cart item object, or undefined if not found.
*/
export const getCartItem = ( state, cartItemKey ) => {
return state.cartData.items.find(
( cartItem ) => cartItem.key === cartItemKey
);
};
/**
* Returns true if the specified cart item quantity is being updated.
*
* @param {Object} state The current state.
* @param {string} cartItemKey Key for a cart item.
* @return {boolean} True if a item has a pending request to be updated.
*/
export const isItemPendingQuantity = ( state, cartItemKey ) => {
return state.cartItemsPendingQuantity.includes( cartItemKey );
};
/**
* Returns true if the specified cart item quantity is being updated.
*
* @param {Object} state The current state.
* @param {string} cartItemKey Key for a cart item.
* @return {boolean} True if a item has a pending request to be updated.
*/
export const isItemPendingDelete = ( state, cartItemKey ) => {
return state.cartItemsPendingDelete.includes( cartItemKey );
};
/**
* Retrieves if the address is being applied for shipping.
*
* @param {Object} state The current state.
* @return {boolean} are shipping rates loading.
*/
export const isCustomerDataUpdating = ( state ) => {
return !! state.metaData.updatingCustomerData;
};
/**
* Retrieves if the shipping rate selection is being persisted.
*
* @param {Object} state The current state.
*
* @return {boolean} True if the shipping rate selection is being persisted to
* the server.
*/
export const isShippingRateBeingSelected = ( state ) => {
return !! state.metaData.updatingSelectedRate;
};

View File

@ -0,0 +1,155 @@
/**
* External dependencies
*/
import type { Cart, CartTotals, CartMeta, CartItem } from '@woocommerce/types';
/**
* Internal dependencies
*/
import { CartState, defaultCartState } from '../default-states';
import { ResponseError } from '../types';
/**
* Retrieves cart data from state.
*
* @param {CartState} state The current state.
* @return {Cart} The data to return.
*/
export const getCartData = ( state: CartState ): Cart => {
return state.cartData;
};
/**
* Retrieves cart totals from state.
*
* @param {CartState} state The current state.
* @return {CartTotals} The data to return.
*/
export const getCartTotals = ( state: CartState ): CartTotals => {
return state.cartData.totals || defaultCartState.cartData.totals;
};
/**
* Retrieves cart meta from state.
*
* @param {CartState} state The current state.
* @return {CartMeta} The data to return.
*/
export const getCartMeta = ( state: CartState ): CartMeta => {
return state.metaData || defaultCartState.metaData;
};
/**
* Retrieves cart errors from state.
*
* @param {CartState} state The current state.
* @return {Array<ResponseError>} Array of errors.
*/
export const getCartErrors = ( state: CartState ): Array< ResponseError > => {
return state.errors || [];
};
/**
* Returns true if any coupon is being applied.
*
* @param {CartState} state The current state.
* @return {boolean} True if a coupon is being applied.
*/
export const isApplyingCoupon = ( state: CartState ): boolean => {
return !! state.metaData.applyingCoupon;
};
/**
* Retrieves the coupon code currently being applied.
*
* @param {CartState} state The current state.
* @return {string} The data to return.
*/
export const getCouponBeingApplied = ( state: CartState ): string => {
return state.metaData.applyingCoupon || '';
};
/**
* Returns true if any coupon is being removed.
*
* @param {CartState} state The current state.
* @return {boolean} True if a coupon is being removed.
*/
export const isRemovingCoupon = ( state: CartState ): boolean => {
return !! state.metaData.removingCoupon;
};
/**
* Retrieves the coupon code currently being removed.
*
* @param {CartState} state The current state.
* @return {string} The data to return.
*/
export const getCouponBeingRemoved = ( state: CartState ): string => {
return state.metaData.removingCoupon || '';
};
/**
* Returns cart item matching specified key.
*
* @param {CartState} state The current state.
* @param {string} cartItemKey Key for a cart item.
* @return {CartItem | void} Cart item object, or undefined if not found.
*/
export const getCartItem = (
state: CartState,
cartItemKey: string
): CartItem | void => {
return state.cartData.items.find(
( cartItem ) => cartItem.key === cartItemKey
);
};
/**
* Returns true if the specified cart item quantity is being updated.
*
* @param {CartState} state The current state.
* @param {string} cartItemKey Key for a cart item.
* @return {boolean} True if a item has a pending request to be updated.
*/
export const isItemPendingQuantity = (
state: CartState,
cartItemKey: string
): boolean => {
return state.cartItemsPendingQuantity.includes( cartItemKey );
};
/**
* Returns true if the specified cart item quantity is being updated.
*
* @param {CartState} state The current state.
* @param {string} cartItemKey Key for a cart item.
* @return {boolean} True if a item has a pending request to be updated.
*/
export const isItemPendingDelete = (
state: CartState,
cartItemKey: string
): boolean => {
return state.cartItemsPendingDelete.includes( cartItemKey );
};
/**
* Retrieves if the address is being applied for shipping.
*
* @param {CartState} state The current state.
* @return {boolean} are shipping rates loading.
*/
export const isCustomerDataUpdating = ( state: CartState ): boolean => {
return !! state.metaData.updatingCustomerData;
};
/**
* Retrieves if the shipping rate selection is being persisted.
*
* @param {CartState} state The current state.
*
* @return {boolean} True if the shipping rate selection is being persisted to
* the server.
*/
export const isShippingRateBeingSelected = ( state: CartState ): boolean => {
return !! state.metaData.updatingSelectedRate;
};

View File

@ -1,4 +1,22 @@
export const defaultCartState = {
/**
* External dependencies
*/
import type { Cart, CartMeta } from '@woocommerce/types';
/**
* Internal dependencies
*/
import type { ResponseError } from './types';
export interface CartState {
cartItemsPendingQuantity: Array< string >;
cartItemsPendingDelete: Array< string >;
cartData: Cart;
metaData: CartMeta;
errors: Array< ResponseError >;
}
export const defaultCartState: CartState = {
cartItemsPendingQuantity: [],
cartItemsPendingDelete: [],
cartData: {
@ -15,11 +33,26 @@ export const defaultCartState = {
postcode: '',
country: '',
},
billingAddress: {
first_name: '',
last_name: '',
company: '',
address_1: '',
address_2: '',
city: '',
state: '',
postcode: '',
country: '',
phone: '',
email: '',
},
items: [],
fees: [],
itemsCount: 0,
itemsWeight: 0,
needsShipping: true,
needsPayment: false,
hasCalculatedShipping: true,
fees: [],
totals: {
currency_code: '',
currency_symbol: '',
@ -40,7 +73,15 @@ export const defaultCartState = {
total_tax: '0',
tax_lines: [],
},
errors: [],
paymentRequirements: [],
extensions: [],
},
metaData: {
updatingCustomerData: false,
updatingSelectedRate: false,
applyingCoupon: '',
removingCoupon: '',
},
metaData: {},
errors: [],
};

View File

@ -2,17 +2,24 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import triggerFetch from '@wordpress/api-fetch';
import triggerFetch, { APIFetchOptions } from '@wordpress/api-fetch';
export interface ApiFetchWithHeadersAction {
type: string;
options: APIFetchOptions;
}
/**
* Dispatched a control action for triggering an api fetch call with no parsing.
* Typically this would be used in scenarios where headers are needed.
*
* @param {Object} options The options for the API request.
* @param {APIFetchOptions} options The options for the API request.
*
* @return {Object} The control action descriptor.
* @return {ApiFetchWithHeadersAction} The control action descriptor.
*/
export const apiFetchWithHeaders = ( options ) => {
export const apiFetchWithHeaders = (
options: APIFetchOptions
): ApiFetchWithHeadersAction => {
return {
type: 'API_FETCH_WITH_HEADERS',
options,
@ -37,7 +44,11 @@ const invalidJsonError = {
* the controls property of the registration object.
*/
export const controls = {
API_FETCH_WITH_HEADERS( { options } ) {
API_FETCH_WITH_HEADERS( {
options,
}: {
options: APIFetchOptions;
} ): Promise< unknown > {
return new Promise( ( resolve, reject ) => {
triggerFetch( { ...options, parse: false } )
.then( ( fetchResponse ) => {
@ -48,6 +59,8 @@ export const controls = {
response,
headers: fetchResponse.headers,
} );
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- this does exist but doesn't appear to be typed in the api-fetch types.
triggerFetch.setNonce( fetchResponse.headers );
} )
.catch( () => {
@ -55,12 +68,14 @@ export const controls = {
} );
} )
.catch( ( errorResponse ) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore -- this does exist but doesn't appear to be typed in the api-fetch types.
triggerFetch.setNonce( errorResponse.headers );
if ( typeof errorResponse.json === 'function' ) {
// Parse error response before rejecting it.
errorResponse
.json()
.then( ( error ) => {
.then( ( error: unknown ) => {
reject( error );
} )
.catch( () => {

View File

@ -0,0 +1,6 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {},
"include": [ ".", "../type-defs/**.ts" ],
"exclude": [ "**/test/**" ]
}

View File

@ -0,0 +1,8 @@
export interface ResponseError {
code: string;
message: string;
data: {
status: number;
[ key: string ]: unknown;
};
}

View File

@ -0,0 +1,193 @@
/* eslint-disable camelcase -- API responses have camelcase properties */
export interface CurrencyResponseInfo {
currency_code: string;
currency_symbol: string;
currency_minor_unit: number;
currency_decimal_separator: string;
currency_thousand_separator: string;
currency_prefix: string;
currency_suffix: string;
}
export interface CartResponseTotalsItem extends CurrencyResponseInfo {
total_discount: string;
total_discount_tax: string;
}
export interface CartResponseCouponItem {
code: string;
discount_type: string;
totals: CartResponseTotalsItem;
}
export interface ResponseFirstNameLastName {
first_name: string;
last_name: string;
}
export interface ResponseBaseAddress {
address_1: string;
address_2: string;
city: string;
state: string;
postcode: string;
country: string;
}
export interface ShippingRateItemItem {
key: string;
name: string;
quantity: number;
}
export interface MetaKeyValue {
key: string;
value: string;
}
export interface CartResponseShippingRateItemShippingRate
extends CurrencyResponseInfo {
rate_id: string;
name: string;
description: string;
delivery_time: string;
price: string;
taxes: string;
instance_id: number;
method_id: string;
meta_data: Array< MetaKeyValue >;
selected: boolean;
}
export interface CartResponseShippingRateItem {
package_id: number;
name: string;
destination: ResponseBaseAddress;
items: Array< ShippingRateItemItem >;
shipping_rates: Array< CartResponseShippingRateItemShippingRate >;
}
export interface CartResponseShippingAddress
extends ResponseBaseAddress,
ResponseFirstNameLastName {
company: string;
}
export interface CartResponseBillingAddress
extends CartResponseShippingAddress {
phone: string;
email: string;
}
export interface CartResponseImageItem {
id: number;
src: string;
thumbnail: string;
srcset: string;
sizes: string;
name: string;
alt: string;
}
export interface CartResponseVariationItem {
attribute: string;
value: string;
}
export interface CartResponseItemPrices extends CurrencyResponseInfo {
price: string;
regular_price: string;
sale_price: string;
price_range: null | { min_amount: string; max_amount: string };
raw_prices: {
precision: number;
price: string;
regular_price: string;
sale_price: string;
};
}
export interface CartResponseItemTotals extends CurrencyResponseInfo {
line_subtotal: string;
line_subtotal_tax: string;
line_total: string;
line_total_tax: string;
}
export interface CartResponseItem {
key: string;
id: number;
quantity: number;
quantity_limit: number;
name: string;
summary: string;
short_description: string;
description: string;
sku: string;
low_stock_remaining: string;
backorders_allowed: boolean;
show_backorder_badge: boolean;
sold_individually: boolean;
permalink: string;
images: Array< CartResponseImageItem >;
variation: Array< CartResponseVariationItem >;
prices: CartResponseItemPrices;
totals: CartResponseItemTotals;
}
export interface CartResponseTotalsTaxLineItem {
name: string;
price: string;
}
export interface CartResponseFeeItemTotals extends CurrencyResponseInfo {
total: string;
total_tax: string;
}
export interface CartResponseFeeItem {
id: string;
name: string;
totals: CartResponseFeeItemTotals;
}
export interface CartResponseTotals extends CurrencyResponseInfo {
total_items: string;
total_items_tax: string;
total_fees: string;
total_fees_tax: string;
total_discount: string;
total_discount_tax: string;
total_shipping: string;
total_shipping_tax: string;
total_price: string;
total_tax: string;
tax_lines: Array< CartResponseTotalsTaxLineItem >;
}
export interface CartResponseErrorItem {
code: string;
message: string;
}
export interface CartResponseExtensionItem {
[ key: string ]: unknown;
}
export interface CartResponse {
coupons: Array< CartResponseCouponItem >;
shipping_rates: Array< CartResponseShippingRateItem >;
shipping_address: CartResponseShippingAddress;
billing_address: CartResponseBillingAddress;
items: Array< CartResponseItem >;
items_count: number;
items_weight: number;
needs_payment: boolean;
needs_shipping: boolean;
has_calculated_shipping: boolean;
fees: Array< CartResponseFeeItem >;
totals: CartResponseTotalsItem;
errors: Array< CartResponseErrorItem >;
payment_requirements: Array< unknown >;
extensions: Array< CartResponseExtensionItem >;
}

View File

@ -0,0 +1,188 @@
/* eslint-disable camelcase -- API responses have camelcase properties */
/**
* Internal dependencies
*/
import { MetaKeyValue, ShippingRateItemItem } from './cart-response';
export interface CurrencyInfo {
currency_code: string;
currency_symbol: string;
currency_minor_unit: number;
currency_decimal_separator: string;
currency_thousand_separator: string;
currency_prefix: string;
currency_suffix: string;
}
export interface CartTotalsItem extends CurrencyInfo {
total_discount: string;
total_discount_tax: string;
}
export interface CartCouponItem {
code: string;
discount_type: string;
totals: CartTotalsItem;
}
export interface FirstNameLastName {
first_name: string;
last_name: string;
}
export interface BaseAddress {
address_1: string;
address_2: string;
city: string;
state: string;
postcode: string;
country: string;
}
export interface CartShippingRateItemShippingRate extends CurrencyInfo {
rate_id: string;
name: string;
description: string;
delivery_time: string;
price: string;
taxes: string;
instance_id: number;
method_id: string;
meta_data: Array< MetaKeyValue >;
selected: boolean;
}
export interface CartShippingRateItem {
package_id: number;
name: string;
destination: BaseAddress;
items: Array< ShippingRateItemItem >;
shipping_rates: Array< CartShippingRateItemShippingRate >;
}
export interface CartShippingAddress extends BaseAddress, FirstNameLastName {
company: string;
}
export interface CartBillingAddress extends CartShippingAddress {
phone: string;
email: string;
}
export interface CartImageItem {
id: number;
src: string;
thumbnail: string;
srcset: string;
sizes: string;
name: string;
alt: string;
}
export interface CartVariationItem {
attribute: string;
value: string;
}
export interface CartItemPrices extends CurrencyInfo {
price: string;
regular_price: string;
sale_price: string;
price_range: null | { min_amount: string; max_amount: string };
raw_prices: {
precision: number;
price: string;
regular_price: string;
sale_price: string;
};
}
export interface CartItemTotals extends CurrencyInfo {
line_subtotal: string;
line_subtotal_tax: string;
line_total: string;
line_total_tax: string;
}
export interface CartItem {
key: string;
id: number;
quantity: number;
quantity_limit: number;
name: string;
summary: string;
short_description: string;
description: string;
sku: string;
low_stock_remaining: string;
backorders_allowed: boolean;
show_backorder_badge: boolean;
sold_individually: boolean;
permalink: string;
images: Array< CartImageItem >;
variation: Array< CartVariationItem >;
prices: CartItemPrices;
totals: CartItemTotals;
}
export interface CartTotalsTaxLineItem {
name: string;
price: string;
}
export interface CartFeeItemTotals extends CurrencyInfo {
total: string;
total_tax: string;
}
export interface CartFeeItem {
id: string;
name: string;
totals: CartFeeItemTotals;
}
export interface CartTotals extends CurrencyInfo {
total_items: string;
total_items_tax: string;
total_fees: string;
total_fees_tax: string;
total_discount: string;
total_discount_tax: string;
total_shipping: string;
total_shipping_tax: string;
total_price: string;
total_tax: string;
tax_lines: Array< CartTotalsTaxLineItem >;
}
export interface CartErrorItem {
code: string;
message: string;
}
export interface CartExtensionItem {
[ key: string ]: unknown;
}
export interface Cart {
coupons: Array< CartCouponItem >;
shippingRates: Array< CartShippingRateItem >;
shippingAddress: CartShippingAddress;
billingAddress: CartBillingAddress;
items: Array< CartItem >;
itemsCount: number;
itemsWeight: number;
needsPayment: boolean;
needsShipping: boolean;
hasCalculatedShipping: boolean;
fees: Array< CartFeeItem >;
totals: CartTotals;
errors: Array< CartErrorItem >;
paymentRequirements: Array< unknown >;
extensions: Array< CartExtensionItem >;
}
export interface CartMeta {
updatingCustomerData: boolean;
updatingSelectedRate: boolean;
applyingCoupon: string;
removingCoupon: string;
}

View File

@ -0,0 +1,2 @@
export * from './cart-response';
export * from './cart';

View File

@ -8,5 +8,6 @@ module.exports = {
},
},
],
[ '@babel/preset-typescript' ],
],
};

View File

@ -81,7 +81,7 @@ const getCoreConfig = ( options = {} ) => {
module: {
rules: [
{
test: /\.jsx?$/,
test: /\.(t|j)sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader?cacheDirectory',
@ -123,7 +123,10 @@ woocommerce_blocks_env = ${ NODE_ENV }
`.trim(),
} ),
],
resolve,
resolve: {
...resolve,
extensions: [ '.js', '.ts', '.tsx' ],
},
};
};
@ -169,7 +172,7 @@ const getMainConfig = ( options = {} ) => {
module: {
rules: [
{
test: /\.jsx?$/,
test: /\.(j|t)sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader?cacheDirectory',
@ -210,7 +213,10 @@ const getMainConfig = ( options = {} ) => {
( result ) => ( result.resource = dashIconReplacementModule )
),
],
resolve,
resolve: {
...resolve,
extensions: [ '.js', '.ts', '.tsx' ],
},
};
};
@ -245,7 +251,7 @@ const getFrontConfig = ( options = {} ) => {
module: {
rules: [
{
test: /\.jsx?$/,
test: /\.(j|t)sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader?cacheDirectory',
@ -310,7 +316,10 @@ const getFrontConfig = ( options = {} ) => {
( result ) => ( result.resource = dashIconReplacementModule )
),
],
resolve,
resolve: {
...resolve,
extensions: [ '.js', '.ts', '.tsx' ],
},
};
};
@ -343,7 +352,7 @@ const getPaymentsConfig = ( options = {} ) => {
module: {
rules: [
{
test: /\.jsx?$/,
test: /\.(j|t)sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader?cacheDirectory',
@ -411,7 +420,10 @@ const getPaymentsConfig = ( options = {} ) => {
( result ) => ( result.resource = dashIconReplacementModule )
),
],
resolve,
resolve: {
...resolve,
extensions: [ '.js', '.ts', '.tsx' ],
},
};
};
@ -570,7 +582,10 @@ const getStylingConfig = ( options = {} ) => {
// Remove JS files generated by MiniCssExtractPlugin.
new RemoveFilesPlugin( `./build/*style${ fileSuffix }.js` ),
],
resolve,
resolve: {
...resolve,
extensions: [ '.js', '.ts', '.tsx' ],
},
};
};

View File

@ -1 +0,0 @@
declare var fetchMock: any;

View File

@ -133,15 +133,23 @@
}
},
"@babel/helper-compilation-targets": {
"version": "7.12.16",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.16.tgz",
"integrity": "sha512-dBHNEEaZx7F3KoUYqagIhRIeqyyuI65xMndMZ3WwGwEBI609I4TleYQHcrS627vbKyNTXqShoN+fvYD9HuQxAg==",
"version": "7.12.17",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.17.tgz",
"integrity": "sha512-5EkibqLVYOuZ89BSg2lv+GG8feywLuvMXNYgf0Im4MssE0mFWPztSpJbildNnUgw0bLI2EsIN4MpSHC2iUJkQA==",
"dev": true,
"requires": {
"@babel/compat-data": "^7.12.13",
"@babel/helper-validator-option": "^7.12.16",
"@babel/helper-validator-option": "^7.12.17",
"browserslist": "^4.14.5",
"semver": "^5.5.0"
},
"dependencies": {
"@babel/helper-validator-option": {
"version": "7.12.17",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz",
"integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==",
"dev": true
}
}
},
"@babel/helper-create-class-features-plugin": {
@ -158,9 +166,9 @@
}
},
"@babel/helper-create-regexp-features-plugin": {
"version": "7.12.16",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.16.tgz",
"integrity": "sha512-jAcQ1biDYZBdaAxB4yg46/XirgX7jBDiMHDbwYQOgtViLBXGxJpZQ24jutmBqAIB/q+AwB6j+NbBXjKxEY8vqg==",
"version": "7.12.17",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz",
"integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.12.13",
@ -407,9 +415,9 @@
}
},
"@babel/plugin-proposal-dynamic-import": {
"version": "7.12.16",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.16.tgz",
"integrity": "sha512-yiDkYFapVxNOCcBfLnsb/qdsliroM+vc3LHiZwS4gh7pFjo5Xq3BDhYBNn3H3ao+hWPvqeeTdU+s+FIvokov+w==",
"version": "7.12.17",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.17.tgz",
"integrity": "sha512-ZNGoFZqrnuy9H2izB2jLlnNDAfVPlGl5NhFEiFe4D84ix9GQGygF+CWMGHKuE+bpyS/AOuDQCnkiRNqW2IzS1Q==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.12.13",
@ -3775,6 +3783,12 @@
"@types/node": "*"
}
},
"@types/lodash": {
"version": "4.14.168",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.168.tgz",
"integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==",
"dev": true
},
"@types/markdown-to-jsx": {
"version": "6.11.3",
"resolved": "https://registry.npmjs.org/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz",
@ -3904,9 +3918,10 @@
}
},
"@types/react": {
"version": "16.14.3",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.3.tgz",
"integrity": "sha512-zPrXn03hmPYqh9DznqSFQsoRtrQ4aHgnZDO+hMGvsE/PORvDTdJCHQ6XvJV31ic+0LzF73huPFXUb++W6Kri0Q==",
"version": "16.14.2",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.2.tgz",
"integrity": "sha512-BzzcAlyDxXl2nANlabtT4thtvbbnhee8hMmH/CcJrISDBVcJS1iOsP1f0OAgSdGE0MsY9tqcrb9YoZcOFv9dbQ==",
"dev": true,
"requires": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@ -3915,7 +3930,8 @@
"csstype": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw=="
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==",
"dev": true
}
}
},
@ -4085,6 +4101,12 @@
}
}
},
"@types/wordpress__api-fetch": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/@types/wordpress__api-fetch/-/wordpress__api-fetch-3.2.3.tgz",
"integrity": "sha512-DsbGPr5lB/8ITClw0wt4JBDVff1X2XgkAyFvei2w6s+2HYpEB5GaTqJI4wY/Jn0rWqpFsX68sO5Kl2vKkgyMuw==",
"dev": true
},
"@types/wordpress__data": {
"version": "4.6.9",
"resolved": "https://registry.npmjs.org/@types/wordpress__data/-/wordpress__data-4.6.9.tgz",
@ -4095,6 +4117,16 @@
"redux": "^4.0.1"
}
},
"@types/wordpress__data-controls": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/wordpress__data-controls/-/wordpress__data-controls-1.0.4.tgz",
"integrity": "sha512-PejgPEZNS+tSupgU3mFd3lAdrPJgm8Jvh2uEHjSxTYgDDk7TMjoBOX069sid4kF9ck5nDLqg59UcPUDT0F2PnA==",
"dev": true,
"requires": {
"@types/wordpress__api-fetch": "*",
"@types/wordpress__data": "*"
}
},
"@types/wordpress__element": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@types/wordpress__element/-/wordpress__element-2.4.1.tgz",
@ -4131,6 +4163,233 @@
"@types/node": "*"
}
},
"@typescript-eslint/eslint-plugin": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.1.tgz",
"integrity": "sha512-5JriGbYhtqMS1kRcZTQxndz1lKMwwEXKbwZbkUZNnp6MJX0+OVXnG0kOlBZP4LUAxEyzu3cs+EXd/97MJXsGfw==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "4.14.1",
"@typescript-eslint/scope-manager": "4.14.1",
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.15",
"regexpp": "^3.0.0",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
"dependencies": {
"@nodelib/fs.stat": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
"dev": true
},
"@typescript-eslint/experimental-utils": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.1.tgz",
"integrity": "sha512-2CuHWOJwvpw0LofbyG5gvYjEyoJeSvVH2PnfUQSn0KQr4v8Dql2pr43ohmx4fdPQ/eVoTSFjTi/bsGEXl/zUUQ==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
"@typescript-eslint/scope-manager": "4.14.1",
"@typescript-eslint/types": "4.14.1",
"@typescript-eslint/typescript-estree": "4.14.1",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
}
},
"@typescript-eslint/scope-manager": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.14.1.tgz",
"integrity": "sha512-F4bjJcSqXqHnC9JGUlnqSa3fC2YH5zTtmACS1Hk+WX/nFB0guuynVK5ev35D4XZbdKjulXBAQMyRr216kmxghw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.14.1",
"@typescript-eslint/visitor-keys": "4.14.1"
}
},
"@typescript-eslint/types": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.14.1.tgz",
"integrity": "sha512-SkhzHdI/AllAgQSxXM89XwS1Tkic7csPdndUuTKabEwRcEfR8uQ/iPA3Dgio1rqsV3jtqZhY0QQni8rLswJM2w==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.1.tgz",
"integrity": "sha512-M8+7MbzKC1PvJIA8kR2sSBnex8bsR5auatLCnVlNTJczmJgqRn8M+sAlQfkEq7M4IY3WmaNJ+LJjPVRrREVSHQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.14.1",
"@typescript-eslint/visitor-keys": "4.14.1",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
"lodash": "^4.17.15",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.1.tgz",
"integrity": "sha512-TAblbDXOI7bd0C/9PE1G+AFo7R5uc+ty1ArDoxmrC1ah61Hn6shURKy7gLdRb1qKJmjHkqu5Oq+e4Kt0jwf1IA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.14.1",
"eslint-visitor-keys": "^2.0.0"
}
},
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
"requires": {
"path-type": "^4.0.0"
}
},
"eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"requires": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
}
},
"eslint-visitor-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
"integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
"dev": true
},
"fast-glob": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
"integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.0",
"merge2": "^1.3.0",
"micromatch": "^4.0.2",
"picomatch": "^2.2.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"globby": {
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
"integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==",
"dev": true,
"requires": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.1.1",
"ignore": "^5.1.4",
"merge2": "^1.3.0",
"slash": "^3.0.0"
}
},
"ignore": {
"version": "5.1.8",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
"dev": true
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
"dev": true,
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.0.5"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"semver": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
"@typescript-eslint/experimental-utils": {
"version": "4.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.15.0.tgz",
@ -4157,6 +4416,205 @@
}
}
},
"@typescript-eslint/parser": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.14.1.tgz",
"integrity": "sha512-mL3+gU18g9JPsHZuKMZ8Z0Ss9YP1S5xYZ7n68Z98GnPq02pYNQuRXL85b9GYhl6jpdvUc45Km7hAl71vybjUmw==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "4.14.1",
"@typescript-eslint/types": "4.14.1",
"@typescript-eslint/typescript-estree": "4.14.1",
"debug": "^4.1.1"
},
"dependencies": {
"@nodelib/fs.stat": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
"dev": true
},
"@typescript-eslint/scope-manager": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.14.1.tgz",
"integrity": "sha512-F4bjJcSqXqHnC9JGUlnqSa3fC2YH5zTtmACS1Hk+WX/nFB0guuynVK5ev35D4XZbdKjulXBAQMyRr216kmxghw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.14.1",
"@typescript-eslint/visitor-keys": "4.14.1"
}
},
"@typescript-eslint/types": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.14.1.tgz",
"integrity": "sha512-SkhzHdI/AllAgQSxXM89XwS1Tkic7csPdndUuTKabEwRcEfR8uQ/iPA3Dgio1rqsV3jtqZhY0QQni8rLswJM2w==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.1.tgz",
"integrity": "sha512-M8+7MbzKC1PvJIA8kR2sSBnex8bsR5auatLCnVlNTJczmJgqRn8M+sAlQfkEq7M4IY3WmaNJ+LJjPVRrREVSHQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.14.1",
"@typescript-eslint/visitor-keys": "4.14.1",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
"lodash": "^4.17.15",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.1.tgz",
"integrity": "sha512-TAblbDXOI7bd0C/9PE1G+AFo7R5uc+ty1ArDoxmrC1ah61Hn6shURKy7gLdRb1qKJmjHkqu5Oq+e4Kt0jwf1IA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.14.1",
"eslint-visitor-keys": "^2.0.0"
}
},
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
"requires": {
"path-type": "^4.0.0"
}
},
"eslint-visitor-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
"integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
"dev": true
},
"fast-glob": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
"integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.0",
"merge2": "^1.3.0",
"micromatch": "^4.0.2",
"picomatch": "^2.2.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"globby": {
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
"integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==",
"dev": true,
"requires": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.1.1",
"ignore": "^5.1.4",
"merge2": "^1.3.0",
"slash": "^3.0.0"
}
},
"ignore": {
"version": "5.1.8",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
"dev": true
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
"dev": true,
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.0.5"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"semver": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
"@typescript-eslint/scope-manager": {
"version": "4.15.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.15.0.tgz",
@ -11661,12 +12119,12 @@
"dev": true
},
"core-js-compat": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz",
"integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==",
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.9.0.tgz",
"integrity": "sha512-YK6fwFjCOKWwGnjFUR3c544YsnA/7DoLL0ysncuOJ4pwbriAtOpvM2bygdlcXbvQCQZ7bBU9CL4t7tGl7ETRpQ==",
"dev": true,
"requires": {
"browserslist": "^4.16.1",
"browserslist": "^4.16.3",
"semver": "7.0.0"
},
"dependencies": {
@ -13976,6 +14434,36 @@
"resolve": "^1.13.1"
}
},
"eslint-import-resolver-typescript": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.3.0.tgz",
"integrity": "sha512-MHSXvmj5e0SGOOBhBbt7C+fWj1bJbtSYFAD85Xeg8nvUtuooTod2HQb8bfhE9f5QyyNxEfgzqOYFCvmdDIcCuw==",
"dev": true,
"requires": {
"debug": "^4.1.1",
"glob": "^7.1.6",
"is-glob": "^4.0.1",
"resolve": "^1.17.0",
"tsconfig-paths": "^3.9.0"
},
"dependencies": {
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
}
}
},
"eslint-import-resolver-webpack": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.0.tgz",
@ -31879,9 +32367,9 @@
}
},
"typescript": {
"version": "3.9.7",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
"dev": true
},
"ua-parser-js": {
@ -33438,6 +33926,15 @@
"uuid": "^7.0.2"
},
"dependencies": {
"@types/react": {
"version": "16.14.4",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.4.tgz",
"integrity": "sha512-ETj7GbkPGjca/A4trkVeGvoIakmLV6ZtX3J8dcmOpzKzWVybbrOxanwaIPG71GZwImoMDY6Fq4wIe34lEqZ0FQ==",
"requires": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"@wordpress/compose": {
"version": "3.24.3",
"resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-3.24.3.tgz",
@ -33543,6 +34040,11 @@
"lodash": "^4.17.19"
}
},
"csstype": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw=="
},
"downshift": {
"version": "5.4.7",
"resolved": "https://registry.npmjs.org/downshift/-/downshift-5.4.7.tgz",
@ -33582,6 +34084,15 @@
"use-memo-one": "^1.1.1"
},
"dependencies": {
"@types/react": {
"version": "16.14.4",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.4.tgz",
"integrity": "sha512-ETj7GbkPGjca/A4trkVeGvoIakmLV6ZtX3J8dcmOpzKzWVybbrOxanwaIPG71GZwImoMDY6Fq4wIe34lEqZ0FQ==",
"requires": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"@wordpress/deprecated": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-2.11.1.tgz",
@ -33646,6 +34157,11 @@
"lodash": "^4.17.19"
}
},
"csstype": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw=="
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
@ -33667,6 +34183,20 @@
"react-dom": "^16.13.1"
},
"dependencies": {
"@types/react": {
"version": "16.14.4",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.4.tgz",
"integrity": "sha512-ETj7GbkPGjca/A4trkVeGvoIakmLV6ZtX3J8dcmOpzKzWVybbrOxanwaIPG71GZwImoMDY6Fq4wIe34lEqZ0FQ==",
"requires": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"csstype": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
"integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw=="
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",

View File

@ -40,9 +40,9 @@
"lint:ci": "npm run lint:js && npm run lint:css",
"lint:css": "stylelint 'assets/**/*.scss'",
"lint:css-fix": "stylelint 'assets/**/*.scss' --fix",
"lint:js": "wp-scripts lint-js",
"lint:js:report": "npm run lint:js -- --output-file eslint_report.json --format json",
"lint:js-fix": "eslint assets/js --ext=js,jsx --fix",
"lint:js": "wp-scripts lint-js --ext=js,ts,tsx",
"lint:js:report": "npm run lint:js -- --output-file eslint_report.json --ext=js,ts,tsx --format json",
"lint:js-fix": "eslint assets/js --ext=js,jsx,ts,tsx --fix",
"lint:php": "composer run-script phpcs ./src",
"package-plugin": "rimraf woocommerce-gutenberg-products-block.zip && ./bin/build-plugin-zip.sh",
"package-plugin:dev": "rimraf woocommerce-gutenberg-products-block.zip && ./bin/build-plugin-zip.sh -d",
@ -61,6 +61,7 @@
"test:help": "wp-scripts test-unit-js --help",
"test:update": "wp-scripts test-unit-js --updateSnapshot --config tests/js/jest.config.json",
"test:watch": "npm run test -- --watch",
"ts:check": "tsc --build",
"wp-env": "wp-env",
"wp-env:config": "./bin/wp-env-pre-config.sh"
},
@ -71,6 +72,7 @@
"@babel/plugin-proposal-class-properties": "7.12.13",
"@babel/polyfill": "7.12.1",
"@babel/preset-env": "7.12.16",
"@babel/preset-typescript": "^7.12.7",
"@octokit/graphql": "4.6.0",
"@storybook/addon-a11y": "6.0.28",
"@storybook/addon-actions": "6.0.28",
@ -86,9 +88,14 @@
"@testing-library/react-hooks": "^5.0.3",
"@testing-library/user-event": "12.6.3",
"@types/jest": "26.0.20",
"@types/react": "16.14.3",
"@types/lodash": "^4.14.168",
"@types/react": "16.14.2",
"@types/wordpress__api-fetch": "^3.2.3",
"@types/wordpress__data": "4.6.9",
"@types/wordpress__data-controls": "^1.0.4",
"@types/wordpress__element": "2.4.1",
"@typescript-eslint/eslint-plugin": "^4.14.1",
"@typescript-eslint/parser": "^4.14.1",
"@woocommerce/eslint-plugin": "1.1.0",
"@woocommerce/woocommerce-rest-api": "1.0.1",
"@wordpress/babel-preset-default": "4.18.1",
@ -103,7 +110,7 @@
"@wordpress/element": "2.17.1",
"@wordpress/env": "3.0.0",
"@wordpress/html-entities": "2.8.0",
"@wordpress/i18n": "3.15.0",
"@wordpress/i18n": "^3.15.0",
"@wordpress/is-shallow-equal": "^1.8.0",
"@wordpress/scripts": "13.0.1",
"autoprefixer": "10.2.3",
@ -120,7 +127,8 @@
"cross-env": "6.0.3",
"cssnano": "4.1.10",
"deep-freeze": "0.0.1",
"eslint-import-resolver-webpack": "0.13.0",
"eslint-import-resolver-typescript": "^2.3.0",
"eslint-import-resolver-webpack": "^0.13.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-woocommerce": "file:bin/eslint-plugin-woocommerce",
"eslint-plugin-you-dont-need-lodash-underscore": "6.10.0",
@ -145,7 +153,7 @@
"rimraf": "3.0.2",
"sass-loader": "10.1.0",
"source-map-explorer": "2.5.1",
"typescript": "3.9.7",
"typescript": "^4.1.3",
"webpack": "4.44.2",
"webpack-cli": "3.3.12",
"webpack-rtl-plugin": "2.0.0",
@ -190,7 +198,7 @@
"*.scss": [
"npm run lint:css"
],
"*.js": [
"*.{js,ts,tsx}": [
"prettier --write",
"npm run lint:js"
],

View File

@ -0,0 +1,55 @@
{
"exclude": [ "node_modules"],
"compilerOptions": {
"outDir": "./build",
"sourceMap": true,
"baseUrl": ".",
"module": "esnext",
"emitDeclarationOnly": true,
// Import non-ES modules as default imports.
"esModuleInterop": true,
"resolveJsonModule": true,
// Preserve JSX, allows compatibility with wp-element jsx babel transforms
"jsx": "preserve",
"target": "esnext",
"allowJs": true,
"moduleResolution": "node",
"lib": [ "dom", "esnext" ],
"checkJs": true,
"strict": true,
"strictNullChecks": true,
"allowSyntheticDefaultImports": true,
"composite": true,
"rootDir": ".",
"typeRoots": [ "./node_modules/@types" ],
"types": [],
"paths": {
"@woocommerce/atomic-blocks": [ "assets/js/base/atomic/blocks" ],
"@woocommerce/atomic-blocks/*": [
"assets/js/base/atomic/blocks/*"
],
"@woocommerce/atomic-utils": [ "assets/js/atomic/utils" ],
"@woocommerce/base-components/*": [ "assets/js/base/components/*" ],
"@woocommerce/base-context": [ "assets/js/base/context" ],
"@woocommerce/base-hocs/*": [ "assets/js/base/hocs/*" ],
"@woocommerce/base-hooks": [ "assets/js/base/hooks" ],
"@woocommerce/base-utils": [ "assets/js/base/utils" ],
"@woocommerce/editor-components/*": [
"assets/js/editor-components/*"
],
"@woocommerce/block-data": [ "assets/js/data" ],
"@woocommerce/block-hocs": [ "assets/js/hocs" ],
"@woocommerce/blocks-registry": [ "assets/js/blocks-registry" ],
"@woocommerce/blocks-checkout": [ "packages/checkout" ],
"@woocommerce/block-settings": [ "assets/js/settings/blocks" ],
"@woocommerce/e2e-tests": [ "node_modules/woocommerce/tests/e2e" ],
"@woocommerce/icons": [ "assets/js/icons" ],
"@woocommerce/resource-previews": [ "assets/js/previews" ],
"@woocommerce/knobs": [ "storybook/knobs" ],
"@woocommerce/settings": [ "assets/js/settings/shared" ],
"@woocommerce/shared-context": [ "assets/js/shared/context" ],
"@woocommerce/type-defs/*": [ "assets/js/type-defs/*" ],
"@woocommerce/types": [ "assets/js/type-defs" ]
}
}
}

View File

@ -1,50 +1,6 @@
{
"compilerOptions": {
"baseUrl": ".",
"module": "commonjs",
"moduleResolution": "node",
"lib": [ "dom", "esnext" ],
"allowJs": true,
"checkJs": true,
"noEmit": true,
"traceResolution": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"paths": {
"@woocommerce/atomic-blocks": [ "assets/js/base/atomic/blocks" ],
"@woocommerce/atomic-blocks/*": [
"assets/js/base/atomic/blocks/*"
],
"@woocommerce/atomic-utils": [ "assets/js/atomic/utils" ],
"@woocommerce/base-components/*": [ "assets/js/base/components/*" ],
"@woocommerce/base-context": [ "assets/js/base/context" ],
"@woocommerce/base-hocs/*": [ "assets/js/base/hocs/*" ],
"@woocommerce/base-hooks": [ "assets/js/base/hooks" ],
"@woocommerce/base-utils": [ "assets/js/base/utils" ],
"@woocommerce/editor-components/*": [
"assets/js/editor-components/*"
],
"@woocommerce/block-data": [ "assets/js/data" ],
"@woocommerce/block-hocs": [ "assets/js/hocs" ],
"@woocommerce/blocks-registry": [ "assets/js/blocks-registry" ],
"@woocommerce/blocks-checkout": [ "packages/checkout" ],
"@woocommerce/price-format": [ "packages/prices" ],
"@woocommerce/block-settings": [ "assets/js/settings/blocks" ],
"@woocommerce/e2e-tests": [
"node_modules/woocommerce/tests/e2e"
],
"@woocommerce/icons": [ "assets/js/icons" ],
"@woocommerce/resource-previews": [ "assets/js/previews" ],
"@woocommerce/knobs": [ "storybook/knobs" ],
"@woocommerce/settings": [ "assets/js/settings/shared" ],
"@woocommerce/shared-context": [ "assets/js/shared/context" ],
"@woocommerce/type-defs/*": [ "assets/js/type-defs/*" ]
}
},
"include": [ "./assets/js/**/*.js", "./globals.d.ts" ]
"extends": "./tsconfig.base.json",
"include": [ "./assets/js/**/*" ],
"exclude": [ "./assets/js/data" ],
"references": [ { "path": "./assets/js/data" } ]
}