Skip to content

Commit 8e6196b

Browse files
committed
refactor+fix: weird build issue
1 parent 81e5bd5 commit 8e6196b

File tree

16 files changed

+269
-397
lines changed

16 files changed

+269
-397
lines changed

docs/scripts/api/buildGridSelectorsDocumentation.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,8 @@ export default async function buildGridSelectorsDocumentation(
4848
return null;
4949
}
5050

51-
const parameterSymbol = signature.getParameters()[0];
52-
53-
const firstParamName = project.checker.getTypeOfSymbolAtLocation(
54-
parameterSymbol,
55-
parameterSymbol.valueDeclaration!,
56-
).symbol?.name;
57-
5851
if (
59-
firstParamName !== 'RefObject' ||
52+
!/^[a-z]\w+Selector/.test(symbol.name) ||
6053
symbol.name === 'useGridSelector' // Ignore hook
6154
) {
6255
return null;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { lruMemoize } from 'reselect';
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import { lruMemoize, createSelectorCreator } from 'reselect';
2+
import type { CreateSelectorFunction } from './createSelectorType';
3+
4+
export type { CreateSelectorFunction } from './createSelectorType';
5+
6+
/* eslint-disable no-underscore-dangle */ // __cacheKey__
7+
8+
const reselectCreateSelector = createSelectorCreator({
9+
memoize: lruMemoize,
10+
memoizeOptions: {
11+
maxSize: 1,
12+
equalityCheck: Object.is,
13+
},
14+
});
15+
16+
type SelectorWithArgs = ReturnType<typeof reselectCreateSelector> & { selectorArgs: any[3] };
17+
18+
/* eslint-disable id-denylist */
19+
export const createSelector = ((
20+
a: Function,
21+
b: Function,
22+
c?: Function,
23+
d?: Function,
24+
e?: Function,
25+
f?: Function,
26+
...other: any[]
27+
) => {
28+
if (other.length > 0) {
29+
throw new Error('Unsupported number of selectors');
30+
}
31+
32+
let selector: any;
33+
34+
if (a && b && c && d && e && f) {
35+
selector = (state: any, a1: any, a2: any, a3: any) => {
36+
const va = a(state, a1, a2, a3);
37+
const vb = b(state, a1, a2, a3);
38+
const vc = c(state, a1, a2, a3);
39+
const vd = d(state, a1, a2, a3);
40+
const ve = e(state, a1, a2, a3);
41+
return f(va, vb, vc, vd, ve, a1, a2, a3);
42+
};
43+
} else if (a && b && c && d && e) {
44+
selector = (state: any, a1: any, a2: any, a3: any) => {
45+
const va = a(state, a1, a2, a3);
46+
const vb = b(state, a1, a2, a3);
47+
const vc = c(state, a1, a2, a3);
48+
const vd = d(state, a1, a2, a3);
49+
return e(va, vb, vc, vd, a1, a2, a3);
50+
};
51+
} else if (a && b && c && d) {
52+
selector = (state: any, a1: any, a2: any, a3: any) => {
53+
const va = a(state, a1, a2, a3);
54+
const vb = b(state, a1, a2, a3);
55+
const vc = c(state, a1, a2, a3);
56+
return d(va, vb, vc, a1, a2, a3);
57+
};
58+
} else if (a && b && c) {
59+
selector = (state: any, a1: any, a2: any, a3: any) => {
60+
const va = a(state, a1, a2, a3);
61+
const vb = b(state, a1, a2, a3);
62+
return c(va, vb, a1, a2, a3);
63+
};
64+
} else if (a && b) {
65+
selector = (state: any, a1: any, a2: any, a3: any) => {
66+
const va = a(state, a1, a2, a3);
67+
return b(va, a1, a2, a3);
68+
};
69+
} else if (a) {
70+
selector = a;
71+
} else {
72+
throw new Error('Missing arguments');
73+
}
74+
75+
return selector;
76+
}) as unknown as CreateSelectorFunction;
77+
/* eslint-enable id-denylist */
78+
79+
export const createSelectorMemoized: CreateSelectorFunction = (...selectors: any[]) => {
80+
type CacheKey = { id: number };
81+
82+
const cache = new WeakMap<CacheKey, SelectorWithArgs>();
83+
let nextCacheId = 1;
84+
85+
const combiner = selectors[selectors.length - 1];
86+
const nSelectors = selectors.length - 1 || 1;
87+
// (s1, s2, ..., sN, a1, a2, a3) => { ... }
88+
const argsLength = Math.max(combiner.length - nSelectors, 0);
89+
90+
if (argsLength > 3) {
91+
throw new Error('Unsupported number of arguments');
92+
}
93+
94+
// prettier-ignore
95+
const selector = (state: any, a1: any, a2: any, a3: any) => {
96+
let cacheKey = state.__cacheKey__;
97+
if (!cacheKey) {
98+
cacheKey = { id: nextCacheId };
99+
state.__cacheKey__ = cacheKey;
100+
nextCacheId += 1;
101+
}
102+
103+
let fn = cache.get(cacheKey);
104+
if (!fn) {
105+
let reselectArgs = selectors;
106+
const selectorArgs = [undefined, undefined, undefined];
107+
switch (argsLength) {
108+
case 0:
109+
break;
110+
case 1: {
111+
reselectArgs = [
112+
...selectors.slice(0, -1),
113+
() => selectorArgs[0],
114+
combiner
115+
];
116+
break;
117+
}
118+
case 2: {
119+
reselectArgs = [
120+
...selectors.slice(0, -1),
121+
() => selectorArgs[0],
122+
() => selectorArgs[1],
123+
combiner,
124+
];
125+
break;
126+
}
127+
case 3: {
128+
reselectArgs = [
129+
...selectors.slice(0, -1),
130+
() => selectorArgs[0],
131+
() => selectorArgs[1],
132+
() => selectorArgs[2],
133+
combiner,
134+
];
135+
break;
136+
}
137+
default:
138+
throw new Error('Unsupported number of arguments');
139+
}
140+
141+
fn = reselectCreateSelector(...(reselectArgs as any)) as unknown as SelectorWithArgs;
142+
fn.selectorArgs = selectorArgs;
143+
144+
cache.set(cacheKey, fn);
145+
}
146+
147+
/* eslint-disable no-fallthrough */
148+
149+
switch (argsLength) {
150+
case 3: fn.selectorArgs[2] = a3;
151+
case 2: fn.selectorArgs[1] = a2;
152+
case 1: fn.selectorArgs[0] = a1;
153+
case 0:
154+
default:
155+
}
156+
switch (argsLength) {
157+
case 0: return fn(state);
158+
case 1: return fn(state, a1);
159+
case 2: return fn(state, a1, a2);
160+
case 3: return fn(state, a1, a2, a3);
161+
default:
162+
throw new Error('unreachable');
163+
}
164+
};
165+
166+
return selector as any;
167+
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { Selector } from 'reselect';
2+
3+
export type CreateSelectorFunction = <
4+
const Args extends any[],
5+
const Selectors extends ReadonlyArray<Selector<any>>,
6+
const Combiner extends (...args: readonly [...ReturnTypes<Selectors>, ...Args]) => any,
7+
>(
8+
...items: [...Selectors, Combiner]
9+
) => (
10+
...args: Selectors['length'] extends 0
11+
? MergeParams<ReturnTypes<Selectors>, Parameters<Combiner>>
12+
: [
13+
StateFromSelectorList<Selectors>,
14+
...MergeParams<ReturnTypes<Selectors>, Parameters<Combiner>>,
15+
]
16+
) => ReturnType<Combiner>;
17+
18+
type StateFromSelectorList<Selectors extends readonly any[]> = Selectors extends [
19+
f: infer F,
20+
...other: infer R,
21+
]
22+
? StateFromSelector<F> extends StateFromSelectorList<R>
23+
? StateFromSelector<F>
24+
: StateFromSelectorList<R>
25+
: {};
26+
27+
type StateFromSelector<T> = T extends (first: infer F, ...args: any[]) => any ? F : never;
28+
29+
type Fn = (...args: any[]) => any;
30+
31+
type ReturnTypes<FunctionsArray extends readonly Fn[]> = {
32+
[Index in keyof FunctionsArray]: FunctionsArray[Index] extends FunctionsArray[number]
33+
? ReturnType<FunctionsArray[Index]>
34+
: never;
35+
};
36+
37+
type MergeParams<
38+
STypes extends readonly unknown[],
39+
CTypes extends readonly unknown[],
40+
> = STypes['length'] extends 0 ? CTypes : MergeParams<DropFirst<STypes>, DropFirst<CTypes>>;
41+
42+
type DropFirst<T> = T extends [any, ...infer Xs] ? Xs : [];
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './createSelector';

packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
2-
import { RefObject } from '@mui/x-internals/types';
32
import { lruMemoize } from 'reselect';
3+
import { RefObject } from '@mui/x-internals/types';
44
import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
55
import { isDeepEqual } from '@mui/x-internals/isDeepEqual';
66
import { GridEventListener } from '../../../models/events';

packages/x-data-grid/src/hooks/features/preferencesPanel/gridPreferencePanelSelector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const gridPreferencePanelStateSelector = createRootSelector(
77

88
export const gridPreferencePanelSelectorWithLabel = createSelector(
99
gridPreferencePanelStateSelector,
10-
(panel, labelId: string) => {
10+
(panel, labelId: string | undefined) => {
1111
if (panel.open && panel.labelId === labelId) {
1212
return true;
1313
}

packages/x-data-grid/src/hooks/features/virtualization/gridVirtualizationSelectors.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import { RefObject } from '@mui/x-internals/types';
21
import {
32
createRootSelector,
43
createSelector,
54
createSelectorMemoized,
65
} from '../../../utils/createSelector';
76
import type { GridColumnsRenderContext } from '../../../models/params/gridScrollParams';
87
import { GridStateCommunity } from '../../../models/gridStateCommunity';
9-
import { GridApiCommunity } from '../../../models/api/gridApiCommunity';
108

119
/**
1210
* Get the columns state
@@ -54,17 +52,22 @@ export const gridRenderContextSelector = createSelector(
5452
(state) => state.renderContext,
5553
);
5654

55+
const firstColumnIndexSelector = createRootSelector(
56+
(state: GridStateCommunity) => state.virtualization.renderContext.firstColumnIndex,
57+
);
58+
const lastColumnIndexSelector = createRootSelector(
59+
(state: GridStateCommunity) => state.virtualization.renderContext.lastColumnIndex,
60+
);
61+
5762
/**
5863
* Get the render context, with only columns filled in.
5964
* This is cached, so it can be used to only re-render when the column interval changes.
6065
* @category Virtualization
6166
* @ignore - do not document.
6267
*/
6368
export const gridRenderContextColumnsSelector = createSelectorMemoized(
64-
(apiRef: RefObject<GridApiCommunity>) =>
65-
apiRef.current.state.virtualization.renderContext.firstColumnIndex,
66-
(apiRef: RefObject<GridApiCommunity>) =>
67-
apiRef.current.state.virtualization.renderContext.lastColumnIndex,
69+
firstColumnIndexSelector,
70+
lastColumnIndexSelector,
6871
(firstColumnIndex, lastColumnIndex): GridColumnsRenderContext => ({
6972
firstColumnIndex,
7073
lastColumnIndex,

packages/x-data-grid/src/hooks/utils/useGridSelector.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,8 @@ import { fastObjectShallowCompare } from '@mui/x-internals/fastObjectShallowComp
44
import { warnOnce } from '@mui/x-internals/warning';
55
import { useSyncExternalStore } from 'use-sync-external-store/shim';
66
import type { GridApiCommon } from '../../models/api/gridApiCommon';
7-
import type { OutputSelector } from '../../utils/createSelector';
87
import { useLazyRef } from './useLazyRef';
98

10-
type Selector<Api extends GridApiCommon, Args, T> =
11-
| ((apiRef: RefObject<Api>) => T)
12-
| ((apiRef: RefObject<Api | null>) => T)
13-
| OutputSelector<Api['state'], Args, T>;
14-
159
const defaultCompare = Object.is;
1610
export const objectShallowCompare = fastObjectShallowCompare as (a: unknown, b: unknown) => boolean;
1711
const arrayShallowCompare = (a: any[], b: any[]) => {
@@ -39,19 +33,31 @@ const EMPTY = [] as unknown[];
3933
type Refs<T> = {
4034
state: T;
4135
equals: <U = T>(a: U, b: U) => boolean;
42-
selector: Selector<any, any, T>;
36+
selector: Function;
4337
args: any;
4438
subscription: undefined | (() => void);
4539
};
4640

4741
const emptyGetSnapshot = () => null;
4842

49-
export const useGridSelector = <Api extends GridApiCommon, Args, T>(
43+
export function useGridSelector<Api extends GridApiCommon, T>(
44+
apiRef: RefObject<Api>,
45+
selector: (apiRef: RefObject<Api>) => T,
46+
args?: undefined,
47+
equals?: <U = T>(a: U, b: U) => boolean,
48+
): T;
49+
export function useGridSelector<Api extends GridApiCommon, T, Args>(
5050
apiRef: RefObject<Api>,
51-
selector: Selector<Api, Args, T>,
51+
selector: (apiRef: RefObject<Api>, a1: Args) => T,
52+
args: Args,
53+
equals?: <U = T>(a: U, b: U) => boolean,
54+
): T;
55+
export function useGridSelector<Api extends GridApiCommon, Args, T>(
56+
apiRef: RefObject<Api>,
57+
selector: Function,
5258
args: Args = undefined as Args,
5359
equals: <U = T>(a: U, b: U) => boolean = defaultCompare,
54-
) => {
60+
) {
5561
if (process.env.NODE_ENV !== 'production') {
5662
if (!apiRef.current.state) {
5763
warnOnce([
@@ -116,4 +122,4 @@ export const useGridSelector = <Api extends GridApiCommon, Args, T>(
116122
useSyncExternalStore(unsubscribe, subscribe, emptyGetSnapshot);
117123

118124
return state;
119-
};
125+
}

packages/x-data-grid/src/utils/createSelector.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ createSelector(
1414
);
1515

1616
createSelector(
17-
// @ts-expect-error Missing combiner function
1817
(apiRef: RefObject<GridApiCommunity>) => apiRef.current.state.columns.orderedFields,
18+
// @ts-expect-error Missing combiner function
1919
(apiRef: RefObject<GridApiCommunity>) => apiRef.current.state.columns.lookup,
2020
);
2121

0 commit comments

Comments
 (0)