Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Fix/you do not need lodash #9161

Merged
merged 31 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cbe7bb6
Remove lodash `without` usage
mikejolley Apr 20, 2023
03f3e15
isNumber
mikejolley Apr 20, 2023
4aad2cb
Remove lodash `difference`
mikejolley Apr 20, 2023
d82c042
Replace lodash isEmpty with type guard
mikejolley Apr 20, 2023
7b052a0
Replace isObject with type guard
mikejolley Apr 20, 2023
af2f678
remove lodash noop
mikejolley Apr 20, 2023
d825259
Replace lodash clamp
mikejolley Apr 20, 2023
d095bdb
replace lodash uniqueId
mikejolley Apr 20, 2023
0b099f4
Remove uniqueId import
mikejolley Apr 20, 2023
973e72a
Add eslint rule to restrict lodash import
mikejolley Apr 20, 2023
1f3b269
Replace lodash range
mikejolley Apr 20, 2023
57e20e0
Replace lodash has() function
mikejolley Apr 20, 2023
baf1f28
replace omitby
mikejolley Apr 20, 2023
b738e34
Replace lodash isEqual with fastDeepEqual
mikejolley Apr 20, 2023
612b7b8
Replace kebabCase with change-case package
mikejolley Apr 20, 2023
d490719
Replace lodash camelCase
mikejolley Apr 20, 2023
03a1995
Replace lodash debounce with custom utiity
mikejolley Apr 20, 2023
dfcf149
replace lodash keyby
mikejolley Apr 20, 2023
991984f
Replace lodash pick with native function
mikejolley Apr 21, 2023
0361d8c
Replace lodash cloneDeep with klona
mikejolley Apr 21, 2023
27e6e99
Replace snake case keys package with change case
mikejolley Apr 21, 2023
34326c4
Replace sortBy with fast sort package
mikejolley Apr 21, 2023
2b577a7
replace isEmpty with type guard
mikejolley Apr 21, 2023
5a4628d
Replace pickBy usage in validation reducer
mikejolley Apr 21, 2023
204a72b
Replace groupBy usage in search list control
mikejolley Apr 21, 2023
8391b94
Replace flatten, uniqBy usage in getProducts()
mikejolley Apr 21, 2023
95a8100
Remove setWith and clone from updateState
mikejolley Apr 21, 2023
e9991c9
Replace custom useThrottle with useThrottledCallback from use-debounc…
mikejolley Apr 21, 2023
6df643b
onSelectRate can use-debounce
mikejolley Apr 21, 2023
fb4c398
Fix missing flatten
mikejolley Apr 21, 2023
deb9436
Update assets/js/data/cart/test/push-changes.ts
mikejolley Apr 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,121 @@
const restrictedImports = [
{
name: 'lodash',
importNames: [
'camelCase',
'capitalize',
'castArray',
'chunk',
'clamp',
'clone',
'cloneDeep',
'compact',
'concat',
'countBy',
'debounce',
'deburr',
'defaults',
'defaultTo',
'delay',
'difference',
'differenceWith',
'dropRight',
'each',
'escape',
'escapeRegExp',
'every',
'extend',
'filter',
'find',
'findIndex',
'findKey',
'findLast',
'first',
'flatMap',
'flatten',
'flattenDeep',
'flow',
'flowRight',
'forEach',
'fromPairs',
'has',
'identity',
'includes',
'invoke',
'isArray',
'isBoolean',
'isEqual',
'isFinite',
'isFunction',
'isMatch',
'isNil',
'isNumber',
'isObject',
'isObjectLike',
'isPlainObject',
'isString',
'isUndefined',
'keyBy',
'keys',
'last',
'lowerCase',
'map',
'mapKeys',
'maxBy',
'memoize',
'merge',
'negate',
'noop',
'nth',
'omit',
'omitBy',
'once',
'orderby',
'overEvery',
'partial',
'partialRight',
'pick',
'pickBy',
'random',
'reduce',
'reject',
'repeat',
'reverse',
'setWith',
'size',
'snakeCase',
'some',
'sortBy',
'startCase',
'startsWith',
'stubFalse',
'stubTrue',
'sum',
'sumBy',
'take',
'throttle',
'times',
'toString',
'trim',
'truncate',
'unescape',
'unionBy',
'uniq',
'uniqBy',
'uniqueId',
'uniqWith',
'upperFirst',
'values',
'without',
'words',
'xor',
'zip',
],
message:
'This Lodash method is not recommended. Please use native functionality instead. If using `memoize`, please use `memize` instead.',
},
];

module.exports = {
root: true,
extends: [
Expand Down Expand Up @@ -71,6 +189,12 @@ module.exports = {
allowedTextDomain: [ 'woo-gutenberg-products-block' ],
},
],
'no-restricted-imports': [
'error',
{
paths: restrictedImports,
},
],
'@typescript-eslint/no-restricted-imports': [
'error',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
useAddToCartFormContext,
} from '@woocommerce/base-context';
import { useProductDataContext } from '@woocommerce/shared-context';
import { isEmpty } from 'lodash';
import { isEmpty } from '@woocommerce/types';
import { withProductDataContext } from '@woocommerce/shared-hocs';

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* External dependencies
*/
import { keyBy } from 'lodash';
import { decodeEntities } from '@wordpress/html-entities';
import {
Dictionary,
Expand All @@ -10,6 +9,7 @@ import {
ProductResponseTermItem,
ProductResponseVariationsItem,
} from '@woocommerce/types';
import { keyBy } from '@woocommerce/base-utils';

/**
* Internal dependencies
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { kebabCase } from 'lodash';
import { paramCase as kebabCase } from 'change-case';
import { decodeEntities } from '@wordpress/html-entities';
import type { ProductResponseItemData } from '@woocommerce/types';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
useStoreEvents,
} from '@woocommerce/base-context/hooks';
import { sanitizeHTML } from '@woocommerce/utils';
import { debounce } from 'lodash';
import { useDebouncedCallback } from 'use-debounce';
import type { ReactElement } from 'react';

/**
Expand Down Expand Up @@ -91,23 +91,22 @@ export const ShippingRatesControlPackage = ( {
) }
</>
);
const onSelectRate = debounce(
useCallback(
( newShippingRateId: string ) => {
selectShippingRate( newShippingRateId, packageId );
dispatchCheckoutEvent( 'set-selected-shipping-rate', {
shippingRateId: newShippingRateId,
} );
},
[ dispatchCheckoutEvent, packageId, selectShippingRate ]
),
1000

const onSelectRate = useCallback(
( newShippingRateId: string ) => {
selectShippingRate( newShippingRateId, packageId );
dispatchCheckoutEvent( 'set-selected-shipping-rate', {
shippingRateId: newShippingRateId,
} );
},
[ dispatchCheckoutEvent, packageId, selectShippingRate ]
);
const debouncedOnSelectRate = useDebouncedCallback( onSelectRate, 1000 );
const packageRatesProps = {
className,
noResultsMessage,
rates: packageData.shipping_rates,
onSelectRate,
onSelectRate: debouncedOnSelectRate,
selectedRate: packageData.shipping_rates.find(
( rate ) => rate.selected
),
Expand Down
10 changes: 6 additions & 4 deletions assets/js/base/components/product-list/product-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import { __, _n, sprintf } from '@wordpress/i18n';
import { isEqual } from 'lodash';
import fastDeepEqual from 'fast-deep-equal/es6';
import classnames from 'classnames';
import Pagination from '@woocommerce/base-components/pagination';
import { useEffect } from '@wordpress/element';
Expand Down Expand Up @@ -113,7 +113,9 @@ const announceLoadingCompletion = ( totalProducts: number ): void => {
const areQueryTotalsDifferent: AreQueryTotalsDifferent = (
{ totalQuery: nextQuery, totalProducts: nextProducts },
{ totalQuery: currentQuery } = {}
) => ! isEqual( nextQuery, currentQuery ) && Number.isFinite( nextProducts );
) =>
! fastDeepEqual( nextQuery, currentQuery ) &&
Number.isFinite( nextProducts );

const ProductList = ( {
attributes,
Expand Down Expand Up @@ -169,7 +171,7 @@ const ProductList = ( {

// If query state (excluding pagination/sorting attributes) changed, reset pagination to the first page.
useEffect( () => {
if ( isEqual( totalQuery, previousQueryTotals?.totalQuery ) ) {
if ( fastDeepEqual( totalQuery, previousQueryTotals?.totalQuery ) ) {
return;
}
onPageChange( 1 );
Expand Down Expand Up @@ -210,7 +212,7 @@ const ProductList = ( {
const totalPages =
! Number.isFinite( totalProducts ) &&
Number.isFinite( previousQueryTotals?.totalProducts ) &&
isEqual( totalQuery, previousQueryTotals?.totalQuery )
fastDeepEqual( totalQuery, previousQueryTotals?.totalQuery )
? Math.ceil( ( previousQueryTotals?.totalProducts || 0 ) / perPage )
: Math.ceil( totalProducts / perPage );
const listProducts = products.length
Expand Down
11 changes: 5 additions & 6 deletions assets/js/base/context/event-emit/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/**
* External dependencies
*/
import { uniqueId } from 'lodash';

/**
* Internal dependencies
*/
Expand All @@ -13,14 +8,18 @@ import {
EventObserversType,
} from './types';

export function generateUniqueId() {
return Math.floor( Math.random() * Date.now() ).toString();
}

export const actions = {
addEventCallback: (
eventType: string,
callback: ActionCallbackType,
priority = 10
): ActionType => {
return {
id: uniqueId(),
id: generateUniqueId(),
type: ACTION.ADD_EVENT_CALLBACK,
eventType,
callback,
Expand Down
4 changes: 2 additions & 2 deletions assets/js/base/context/hooks/cart/use-store-cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* External dependencies
*/
import { isEqual } from 'lodash';
import fastDeepEqual from 'fast-deep-equal/es6';
import { useRef } from '@wordpress/element';
import {
CART_STORE_KEY as storeKey,
Expand Down Expand Up @@ -247,7 +247,7 @@ export const useStoreCart = (

if (
! currentResults.current ||
! isEqual( currentResults.current, results )
! fastDeepEqual( currentResults.current, results )
) {
currentResults.current = results;
}
Expand Down
11 changes: 5 additions & 6 deletions assets/js/base/context/hooks/collections/use-collection-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
*/
import { useState, useEffect, useMemo } from '@wordpress/element';
import { useDebounce } from 'use-debounce';
import { isEmpty, sortBy } from 'lodash';
import { isEmpty, objectHasProp } from '@woocommerce/types';
import { sort } from 'fast-sort';
import { useShallowEqual } from '@woocommerce/base-hooks';
import { objectHasProp } from '@woocommerce/types';

/**
* Internal dependencies
Expand All @@ -22,17 +22,16 @@ const buildCollectionDataQuery = (
if (
Array.isArray( collectionDataQueryState.calculate_attribute_counts )
) {
query.calculate_attribute_counts = sortBy(
query.calculate_attribute_counts = sort(
collectionDataQueryState.calculate_attribute_counts.map(
( { taxonomy, queryType } ) => {
return {
taxonomy,
query_type: queryType,
};
}
),
[ 'taxonomy', 'query_type' ]
);
)
).asc( [ 'taxonomy', 'query_type' ] );
}

return query;
Expand Down
12 changes: 12 additions & 0 deletions assets/js/base/utils/camel-case-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* External dependencies
*/
import { camelCase } from 'change-case';

/**
* Internal dependencies
*/
import { mapKeys } from './map-keys';

export const camelCaseKeys = ( obj: object ) =>
mapKeys( obj, ( _, key ) => camelCase( key ) );
34 changes: 34 additions & 0 deletions assets/js/base/utils/debounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type DebouncedFunction< T extends ( ...args: any[] ) => any > = ( (
...args: Parameters< T >
) => void ) & { flush: () => void };

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const debounce = < T extends ( ...args: any[] ) => any >(
func: T,
wait: number,
immediate?: boolean
): DebouncedFunction< T > => {
let timeout: ReturnType< typeof setTimeout > | null;
let latestArgs: Parameters< T > | null = null;

const debounced = ( ( ...args: Parameters< T > ) => {
latestArgs = args;
if ( timeout ) clearTimeout( timeout );
timeout = setTimeout( () => {
timeout = null;
if ( ! immediate && latestArgs ) func( ...latestArgs );
}, wait );
if ( immediate && ! timeout ) func( ...args );
} ) as DebouncedFunction< T >;

debounced.flush = () => {
if ( timeout && latestArgs ) {
func( ...latestArgs );
clearTimeout( timeout );
timeout = null;
}
};

return debounced;
};
5 changes: 5 additions & 0 deletions assets/js/base/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ export * from './get-icons-from-payment-methods';
export * from './parse-style';
export * from './create-notice';
export * from './get-navigation-type';
export * from './map-keys';
export * from './camel-case-keys';
export * from './snake-case-keys';
export * from './debounce';
export * from './keyby';
7 changes: 7 additions & 0 deletions assets/js/base/utils/keyby.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const keyBy = < T >( array: T[], key: keyof T ) => {
return array.reduce( ( acc, value ) => {
const computedKey = key ? String( value[ key ] ) : String( value );
acc[ computedKey ] = value;
return acc;
}, {} as Record< string, T > );
};
Loading