Skip to content

Commit 0b711ef

Browse files
authored
Merge pull request #70 from webKrafters/upgrade-cache
Upgrade cache
2 parents 82776e2 + 553cca6 commit 0b711ef

13 files changed

Lines changed: 2166 additions & 3108 deletions

File tree

jest.config.js

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
module.exports = {
2-
collectCoverageFrom: [
3-
'src/**/*.ts'
4-
],
5-
coveragePathIgnorePatterns: [
6-
'src/constants',
7-
'src/test-artifacts',
8-
'src/main/test-apps',
9-
'src/index.ts'
10-
],
11-
globals: {
12-
'ts-jest': {
13-
tsConfig: 'tsconfig.json',
14-
diagnostics: false,
15-
},
16-
},
17-
setupFiles: [
18-
'<rootDir>/setupTests.js'
19-
],
20-
testEnvironment: 'jsdom',
21-
testEnvironmentOptions: {
22-
url: 'http://localhost/'
23-
},
24-
transform: {
25-
'\\.[jt]sx?$': 'ts-jest'
26-
}
2+
collectCoverageFrom: [
3+
'src/**/*.ts',
4+
'src/**/*.tsx'
5+
],
6+
coveragePathIgnorePatterns: [
7+
'src/constants',
8+
'src/test-artifacts',
9+
'src/main/test-apps',
10+
'src/index.ts'
11+
],
12+
globals: {
13+
'ts-jest': {
14+
tsConfig: 'tsconfig.json',
15+
diagnostics: false
16+
}
17+
},
18+
setupFiles: [
19+
'<rootDir>/setupTests.js'
20+
],
21+
testEnvironment: 'jsdom',
22+
testEnvironmentOptions: {
23+
url: 'http://localhost/'
24+
},
25+
transform: {
26+
'\\.[jt]sx?$': 'ts-jest'
27+
}
2728
};
28-

package-lock.json

Lines changed: 1662 additions & 2783 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
"@testing-library/user-event": "^14.4.3",
2222
"@types/jest": "^29.5.12",
2323
"@types/jest-cli": "^24.3.0",
24+
"@types/lodash.isempty": "^4.4.9",
2425
"@types/node": "^20.11.28",
25-
"@webkrafters/auto-immutable": "^1.0.3",
2626
"@webkrafters/clone-total": "^1.0.1",
2727
"@webkrafters/data-distillery": "^0.1.1",
28+
"@webkrafters/get-property": "^2.0.0",
2829
"@webkrafters/path-dotize": "0.0.2",
2930
"babel-loader": "^9.1.3",
3031
"eslint": "^8.57.0",
@@ -54,20 +55,20 @@
5455
},
5556
"files": [
5657
"logo.png",
57-
"dist/main/hooks/use-store/index.js",
58-
"dist/main/hooks/use-store/index.d.ts",
59-
"dist/main/hooks/use-render-key-provider/index.js",
60-
"dist/main/hooks/use-render-key-provider/index.d.ts",
61-
"dist/main/hooks/use-prehooks-ref/index.js",
62-
"dist/main/hooks/use-prehooks-ref/index.d.ts",
63-
"dist/model/storage/index.js",
64-
"dist/model/storage/index.d.ts",
65-
"dist/main/index.js",
66-
"dist/main/index.d.ts",
67-
"dist/index.js",
68-
"dist/index.d.ts",
69-
"dist/constants.js",
70-
"dist/constants.d.ts"
58+
"dist\\main\\hooks\\use-store\\index.js",
59+
"dist\\main\\hooks\\use-store\\index.d.ts",
60+
"dist\\main\\hooks\\use-render-key-provider\\index.js",
61+
"dist\\main\\hooks\\use-render-key-provider\\index.d.ts",
62+
"dist\\main\\hooks\\use-prehooks-ref\\index.js",
63+
"dist\\main\\hooks\\use-prehooks-ref\\index.d.ts",
64+
"dist\\model\\storage\\index.js",
65+
"dist\\model\\storage\\index.d.ts",
66+
"dist\\main\\index.js",
67+
"dist\\main\\index.d.ts",
68+
"dist\\index.js",
69+
"dist\\index.d.ts",
70+
"dist\\constants.js",
71+
"dist\\constants.d.ts"
7172
],
7273
"homepage": "https://eagleeye.js.org",
7374
"keywords": [
@@ -93,7 +94,6 @@
9394
"name": "@webkrafters/react-observable-context",
9495
"peerDependencies": {
9596
"@types/react": ">= 16.8.0",
96-
"@webkrafters/auto-immutable": "^1.0.2",
9797
"@webkrafters/clone-total": "^1.0.1",
9898
"@webkrafters/data-distillery": "^0.0.3",
9999
"@webkrafters/path-dotize": "^0.0.2",
@@ -120,5 +120,8 @@
120120
"test:watch": "eslint --fix && jest --updateSnapshot --watchAll"
121121
},
122122
"types": "dist/index.d.ts",
123-
"version": "5.0.4"
124-
}
123+
"version": "6.0.0-rc.0",
124+
"dependencies": {
125+
"@webkrafters/auto-immutable": "^2.0.0-rc.9"
126+
}
127+
}

setupTests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import 'setimmediate';
1+
import 'setimmediate';

src/constants.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@ export {
1212
} from '@webkrafters/auto-immutable';
1313

1414
export const FULL_STATE_SELECTOR = '@@STATE';
15-

src/index.ts

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {
22
ComponentType,
3-
Context,
43
ForwardRefExoticComponent,
54
MemoExoticComponent,
65
NamedExoticComponent,
@@ -13,7 +12,8 @@ import type {
1312
Changes as BaseChanges,
1413
Connection,
1514
Immutable,
16-
Value,
15+
KeyType,
16+
Value
1717
} from '@webkrafters/auto-immutable';
1818

1919
import { FULL_STATE_SELECTOR } from './constants';
@@ -36,16 +36,12 @@ export type {
3636

3737
export type State = Value;
3838

39-
export type ObservableContext<T extends State> = IObservableContext<T> | PublicObservableContext<T>;
40-
41-
export type PublicObservableContext<T extends State> = WithObservableProvider<Context<Store<T>>, T>;
42-
43-
export type IObservableContext<T extends State> = WithObservableProvider<Context<IStore>, T>;
44-
45-
export type WithObservableProvider<
46-
LOCAL_DATA extends Record<any, any> = {},
47-
T extends State = State
48-
> = LOCAL_DATA & { Provider: ObservableProvider<T> };
39+
export type Listener<T extends State = {}> = (
40+
changes : Readonly<T>,
41+
hasChangedPath : (
42+
pathTokens : Array<string>
43+
) => boolean
44+
) => void;
4945

5046
export type ObservableProvider<T extends State> = ForwardRefExoticComponent<
5147
ProviderProps<T> &
@@ -81,7 +77,12 @@ export type PropsExtract<C, STATE extends State, SELECTOR_MAP extends SelectorMa
8177
? U extends OwnProps ? U : IProps
8278
: IProps;
8379

84-
export type InjectedProps<P extends IProps = IProps> = {[K in keyof P]: P[K]};
80+
export type ExtractInjectedProps<
81+
STATE extends State = State,
82+
SELECTOR_MAP extends SelectorMap = SelectorMap,
83+
ALL_PROPS extends OwnProps = OwnProps
84+
> = Omit<ALL_PROPS, keyof Store<STATE>|keyof SELECTOR_MAP>
85+
8586

8687
export interface IProps { ref?: unknown }
8788

@@ -97,12 +98,51 @@ export type ArraySelector = Array<Text | FullStateSelector>;
9798

9899
export type SelectorMap = ObjectSelector | ArraySelector | void;
99100

100-
export type Data<SELECTOR_MAP extends SelectorMap> = (
101+
type ReplacePathSeps<
102+
P extends Text,
103+
T extends string,
104+
> = P extends `${infer U}${T}${infer V}`
105+
? ReplacePathSeps<`${U}.${V}`, T>
106+
: P;
107+
108+
type TrimPathSep<P extends Text> = P extends `${infer U}]${never}` ? U : P;
109+
110+
type NormalizePath<P extends Text> = TrimPathSep<
111+
ReplacePathSeps<
112+
ReplacePathSeps<
113+
ReplacePathSeps<
114+
P,
115+
']['
116+
>,
117+
'].'
118+
>,
119+
'['
120+
>
121+
>;
122+
123+
type Datum<
124+
P extends Text,
125+
S extends Record<Text, any> = State
126+
> = P extends `${infer K}.${infer P_1}`
127+
? Datum<P_1, S[K]>
128+
: P extends ''
129+
? S
130+
: any;
131+
132+
type DataPoint<
133+
P extends Text,
134+
S extends State
135+
> = P extends FullStateSelector ? S : Datum<NormalizePath<P>, S>;
136+
137+
export type Data<
138+
SELECTOR_MAP extends SelectorMap,
139+
STATE extends State = State
140+
> = (
101141
SELECTOR_MAP extends ObjectSelector
102-
? { [selectorKey in keyof SELECTOR_MAP]: Readonly<any> }
142+
? {[ S_KEY in keyof SELECTOR_MAP ] : DataPoint<SELECTOR_MAP[S_KEY], STATE> }
103143
: SELECTOR_MAP extends ArraySelector
104-
? { [selectorKey: number]: Readonly<any> }
105-
: never
144+
? {[ S_NUM : number ] : DataPoint<SELECTOR_MAP[number], STATE>}
145+
: Array<any>
106146
);
107147

108148
export type Changes<T extends State = State> = BaseChanges<T>;
@@ -116,9 +156,7 @@ export interface IStorage<T extends State = State> {
116156

117157
export type NonReactUsageReport = (...args: Array<unknown>) => void;
118158

119-
export type Listener = <T extends State>(changes: Changes<T>) => void;
120-
121-
export type PartialState<T extends State> = Partial<T>;
159+
export type PartialState<T extends State> = T extends Partial<infer U> ? T : Partial<T>;
122160

123161
export interface Prehooks<T extends State = State> {
124162
resetState?: (
@@ -131,6 +169,8 @@ export interface Prehooks<T extends State = State> {
131169
setState?: (newChanges: Changes<T>) => boolean;
132170
};
133171

172+
export type Subscribe = <T extends State>( listener : Listener<T> ) => Unsubscribe;
173+
134174
export type Unsubscribe = (...args: Array<unknown>) => void;
135175

136176
export interface IStore {
@@ -152,10 +192,10 @@ export interface Store<
152192
};
153193

154194
export interface StoreInternal<T extends State> extends IStoreInternal {
155-
cache: Immutable<T>,
195+
cache: Immutable<Partial<T>>,
156196
resetState: (connection: Connection<T>, propertyPaths?: Array<string>) => void;
157197
setState: (connection: Connection<T>, changes: Changes<T>) => void;
158-
subscribe: (listener: Listener) => Unsubscribe;
198+
subscribe: Subscribe;
159199
};
160200

161201
export interface StorePlaceholder extends IStoreInternal {
@@ -169,7 +209,7 @@ export interface StoreRef<T extends State = State> extends StorePlaceholder {
169209
getState: () => T,
170210
resetState: (propertyPaths?: string[]) => void;
171211
setState: (changes: Changes<T>) => void;
172-
subscribe: (listener: Listener) => Unsubscribe;
212+
subscribe: Subscribe;
173213
}
174214

175215
export {
@@ -188,6 +228,7 @@ export {
188228
export {
189229
connect,
190230
createContext,
231+
ObservableContext,
191232
UsageError,
192233
useContext
193-
} from './main';
234+
} from './main';

src/main/hooks/use-render-key-provider/index.test.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import clonedeep from '@webkrafters/clone-total';
22

3+
import { SelectorMap } from '../../..';
4+
35
import useRenderKeyProvider from '.';
46

57
import { renderHook } from '@testing-library/react';
68

79
import '../../../test-artifacts/suppress-render-compat';
810

911
describe( 'useRenderKeyProvider', () => {
10-
let selectorMap;
12+
let selectorMap : SelectorMap;
1113
beforeAll(() => { selectorMap = { _a: 'a', _b: 'b', _c: 'c' } });
1214
test( 'calculates new selectors for new selectorMap', () => {
1315
const initialProps = clonedeep( selectorMap );
@@ -20,14 +22,17 @@ describe( 'useRenderKeyProvider', () => {
2022
expect( result.current ).not.toBe( selectors );
2123
} );
2224
test( 'ensures no abrupt updates to selectors for new list with same selectorMap', () => {
23-
const { result, rerender } = renderHook( useRenderKeyProvider, { initialProps: selectorMap } );
25+
const { result, rerender } = renderHook(
26+
useRenderKeyProvider, {
27+
initialProps: selectorMap
28+
}
29+
);
2430
const selectors = result.current;
2531
rerender( clonedeep( selectorMap ) );
2632
expect( result.current ).toBe( selectors );
2733
} );
2834
describe( 'productive call', () => {
29-
let expected;
30-
beforeAll(() => { expected = [ 'a', 'b', 'c' ] } );
35+
let expected = [ 'a', 'b', 'c' ];
3136
test.each([
3237
[ 'object', { _a: 'a', _b: 'b', _c: 'c' } ],
3338
[ 'array', [ 'a', 'b', 'c' ] ]
@@ -43,6 +48,7 @@ describe( 'useRenderKeyProvider', () => {
4348
[ '{}', {} ]
4449
])( 'empty selectoMap = %s', ( label, value ) => {
4550
test( 'returns empty renderKeys list', () => {
51+
// @ts-expect-error
4652
const { result } = renderHook( useRenderKeyProvider, { initialProps: value } );
4753
expect( result.current ).toEqual([]);
4854
} );
@@ -59,9 +65,9 @@ describe( 'useRenderKeyProvider', () => {
5965
test( 'throws Type error', () => {
6066
try {
6167
renderHook( useRenderKeyProvider, {
62-
initialProps: value as unknown
68+
initialProps: value as unknown as SelectorMap
6369
} );
64-
} catch( e ) {
70+
} catch( e : any ) {
6571
expect( e.constructor.name ).toEqual( 'TypeError' );
6672
expect( e.message ).toEqual( 'Incompatible Selector Map type provided.' );
6773
}

src/main/hooks/use-render-key-provider/index.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type {
55
Text
66
} from '../../..';
77

8-
import { useRef } from 'react';
8+
import { useMemo, useRef } from 'react';
99

1010
import isPlainObject from 'lodash.isplainobject';
1111

@@ -26,13 +26,15 @@ function useRenderKeyProvider( selectorMap : ObjectSelector ) : Array<Text>;
2626
function useRenderKeyProvider( selectorMap : SelectorMap ) : Array<Text>;
2727
function useRenderKeyProvider( selectorMap ) : Array<Text> {
2828
const renderKeys = useRef<Array<Text>>([]);
29-
const currKeys = getCurrKeys( selectorMap );
30-
if( ( renderKeys.current.length !== currKeys.length ||
31-
renderKeys.current.some(( k, i ) => k !== currKeys[ i ])
32-
) ) {
33-
renderKeys.current = currKeys;
34-
}
35-
return renderKeys.current;
29+
return useMemo(() => {
30+
const currKeys = getCurrKeys( selectorMap );
31+
if( ( renderKeys.current.length !== currKeys.length ||
32+
renderKeys.current.some(( k, i ) => k !== currKeys[ i ])
33+
) ) {
34+
renderKeys.current = currKeys;
35+
}
36+
return renderKeys.current;
37+
}, [ selectorMap ]);
3638
};
3739

3840
export default useRenderKeyProvider;

0 commit comments

Comments
 (0)