@wordpress/core-data 4.1.1 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/build/actions.js +1 -1
  4. package/build/actions.js.map +1 -1
  5. package/build/hooks/constants.js +18 -0
  6. package/build/hooks/constants.js.map +1 -0
  7. package/build/hooks/memoize.js +18 -0
  8. package/build/hooks/memoize.js.map +1 -0
  9. package/build/hooks/use-entity-record.js +60 -0
  10. package/build/hooks/use-entity-record.js.map +1 -0
  11. package/build/hooks/use-entity-records.js +67 -0
  12. package/build/hooks/use-entity-records.js.map +1 -0
  13. package/build/hooks/use-query-select.js +130 -0
  14. package/build/hooks/use-query-select.js.map +1 -0
  15. package/build/index.js +34 -3
  16. package/build/index.js.map +1 -1
  17. package/build/resolvers.js +2 -17
  18. package/build/resolvers.js.map +1 -1
  19. package/build/types/attachment.js +6 -0
  20. package/build/types/attachment.js.map +1 -0
  21. package/build/types/base-entity-types.js +47 -0
  22. package/build/types/base-entity-types.js.map +1 -0
  23. package/build/types/comment.js +6 -0
  24. package/build/types/comment.js.map +1 -0
  25. package/build/types/helpers.js +6 -0
  26. package/build/types/helpers.js.map +1 -0
  27. package/build/types/index.js +6 -0
  28. package/build/types/index.js.map +1 -0
  29. package/build/types/menu-location.js +6 -0
  30. package/build/types/menu-location.js.map +1 -0
  31. package/build/types/nav-menu-item.js +6 -0
  32. package/build/types/nav-menu-item.js.map +1 -0
  33. package/build/types/nav-menu.js +6 -0
  34. package/build/types/nav-menu.js.map +1 -0
  35. package/build/types/navigation-area.js +6 -0
  36. package/build/types/navigation-area.js.map +1 -0
  37. package/build/types/page.js +6 -0
  38. package/build/types/page.js.map +1 -0
  39. package/build/types/plugin.js +6 -0
  40. package/build/types/plugin.js.map +1 -0
  41. package/build/types/post.js +6 -0
  42. package/build/types/post.js.map +1 -0
  43. package/build/types/settings.js +6 -0
  44. package/build/types/settings.js.map +1 -0
  45. package/build/types/sidebar.js +6 -0
  46. package/build/types/sidebar.js.map +1 -0
  47. package/build/types/taxonomy.js +6 -0
  48. package/build/types/taxonomy.js.map +1 -0
  49. package/build/types/theme.js +6 -0
  50. package/build/types/theme.js.map +1 -0
  51. package/build/types/type.js +6 -0
  52. package/build/types/type.js.map +1 -0
  53. package/build/types/user.js +6 -0
  54. package/build/types/user.js.map +1 -0
  55. package/build/types/widget-type.js +6 -0
  56. package/build/types/widget-type.js.map +1 -0
  57. package/build/types/widget.js +6 -0
  58. package/build/types/widget.js.map +1 -0
  59. package/build/types/wp-template-part.js +6 -0
  60. package/build/types/wp-template-part.js.map +1 -0
  61. package/build/types/wp-template.js +6 -0
  62. package/build/types/wp-template.js.map +1 -0
  63. package/build-module/actions.js +1 -1
  64. package/build-module/actions.js.map +1 -1
  65. package/build-module/hooks/constants.js +10 -0
  66. package/build-module/hooks/constants.js.map +1 -0
  67. package/build-module/hooks/memoize.js +7 -0
  68. package/build-module/hooks/memoize.js.map +1 -0
  69. package/build-module/hooks/use-entity-record.js +49 -0
  70. package/build-module/hooks/use-entity-record.js.map +1 -0
  71. package/build-module/hooks/use-entity-records.js +56 -0
  72. package/build-module/hooks/use-entity-records.js.map +1 -0
  73. package/build-module/hooks/use-query-select.js +116 -0
  74. package/build-module/hooks/use-query-select.js.map +1 -0
  75. package/build-module/index.js +4 -2
  76. package/build-module/index.js.map +1 -1
  77. package/build-module/resolvers.js +3 -18
  78. package/build-module/resolvers.js.map +1 -1
  79. package/build-module/types/attachment.js +2 -0
  80. package/build-module/types/attachment.js.map +1 -0
  81. package/build-module/types/base-entity-types.js +39 -0
  82. package/build-module/types/base-entity-types.js.map +1 -0
  83. package/build-module/types/comment.js +2 -0
  84. package/build-module/types/comment.js.map +1 -0
  85. package/build-module/types/helpers.js +2 -0
  86. package/build-module/types/helpers.js.map +1 -0
  87. package/build-module/types/index.js +2 -0
  88. package/build-module/types/index.js.map +1 -0
  89. package/build-module/types/menu-location.js +2 -0
  90. package/build-module/types/menu-location.js.map +1 -0
  91. package/build-module/types/nav-menu-item.js +2 -0
  92. package/build-module/types/nav-menu-item.js.map +1 -0
  93. package/build-module/types/nav-menu.js +2 -0
  94. package/build-module/types/nav-menu.js.map +1 -0
  95. package/build-module/types/navigation-area.js +2 -0
  96. package/build-module/types/navigation-area.js.map +1 -0
  97. package/build-module/types/page.js +2 -0
  98. package/build-module/types/page.js.map +1 -0
  99. package/build-module/types/plugin.js +2 -0
  100. package/build-module/types/plugin.js.map +1 -0
  101. package/build-module/types/post.js +2 -0
  102. package/build-module/types/post.js.map +1 -0
  103. package/build-module/types/settings.js +2 -0
  104. package/build-module/types/settings.js.map +1 -0
  105. package/build-module/types/sidebar.js +2 -0
  106. package/build-module/types/sidebar.js.map +1 -0
  107. package/build-module/types/taxonomy.js +2 -0
  108. package/build-module/types/taxonomy.js.map +1 -0
  109. package/build-module/types/theme.js +2 -0
  110. package/build-module/types/theme.js.map +1 -0
  111. package/build-module/types/type.js +2 -0
  112. package/build-module/types/type.js.map +1 -0
  113. package/build-module/types/user.js +2 -0
  114. package/build-module/types/user.js.map +1 -0
  115. package/build-module/types/widget-type.js +2 -0
  116. package/build-module/types/widget-type.js.map +1 -0
  117. package/build-module/types/widget.js +2 -0
  118. package/build-module/types/widget.js.map +1 -0
  119. package/build-module/types/wp-template-part.js +2 -0
  120. package/build-module/types/wp-template-part.js.map +1 -0
  121. package/build-module/types/wp-template.js +2 -0
  122. package/build-module/types/wp-template.js.map +1 -0
  123. package/package.json +5 -4
  124. package/src/actions.js +1 -1
  125. package/src/hooks/constants.ts +7 -0
  126. package/src/hooks/memoize.js +7 -0
  127. package/src/hooks/test/use-entity-record.js +74 -0
  128. package/src/hooks/test/use-entity-records.js +78 -0
  129. package/src/hooks/test/use-query-select.js +194 -0
  130. package/src/hooks/use-entity-record.ts +72 -0
  131. package/src/hooks/use-entity-records.ts +79 -0
  132. package/src/hooks/use-query-select.ts +131 -0
  133. package/src/index.js +3 -1
  134. package/src/resolvers.js +3 -17
  135. package/src/test/resolvers.js +4 -10
  136. package/src/types/README.md +193 -0
  137. package/src/types/attachment.ts +146 -0
  138. package/src/types/base-entity-types.ts +36 -0
  139. package/src/types/comment.ts +96 -0
  140. package/src/types/helpers.ts +153 -0
  141. package/src/types/index.ts +72 -0
  142. package/src/types/menu-location.ts +29 -0
  143. package/src/types/nav-menu-item.ts +106 -0
  144. package/src/types/nav-menu.ts +53 -0
  145. package/src/types/navigation-area.ts +29 -0
  146. package/src/types/page.ts +144 -0
  147. package/src/types/plugin.ts +74 -0
  148. package/src/types/post.ts +153 -0
  149. package/src/types/settings.ts +93 -0
  150. package/src/types/sidebar.ts +60 -0
  151. package/src/types/taxonomy.ts +92 -0
  152. package/src/types/theme.ts +222 -0
  153. package/src/types/type.ts +80 -0
  154. package/src/types/user.ts +109 -0
  155. package/src/types/widget-type.ts +37 -0
  156. package/src/types/widget.ts +64 -0
  157. package/src/types/wp-template-part.ts +94 -0
  158. package/src/types/wp-template.ts +94 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ createReduxStore,
6
+ createRegistry,
7
+ RegistryProvider,
8
+ } from '@wordpress/data';
9
+
10
+ /**
11
+ * External dependencies
12
+ */
13
+ import { act, render } from '@testing-library/react';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+ import useQuerySelect from '../use-query-select';
19
+
20
+ describe( 'useQuerySelect', () => {
21
+ let registry;
22
+ beforeEach( () => {
23
+ jest.useFakeTimers();
24
+
25
+ registry = createRegistry();
26
+ registry.registerStore( 'testStore', {
27
+ reducer: () => ( { foo: 'bar' } ),
28
+ selectors: {
29
+ getFoo: ( state ) => state.foo,
30
+ testSelector: ( state, key ) => state[ key ],
31
+ },
32
+ } );
33
+ } );
34
+
35
+ afterEach( () => {
36
+ jest.runOnlyPendingTimers();
37
+ jest.useRealTimers();
38
+ } );
39
+
40
+ const getTestComponent = ( mapSelectSpy, dependencyKey ) => ( props ) => {
41
+ const dependencies = props[ dependencyKey ];
42
+ mapSelectSpy.mockImplementation( ( select ) => ( {
43
+ results: select( 'testStore' ).testSelector( props.keyName ),
44
+ } ) );
45
+ const data = useQuerySelect( mapSelectSpy, [ dependencies ] );
46
+ return <div>{ data.results.data }</div>;
47
+ };
48
+
49
+ it( 'passes the relevant data to the component', () => {
50
+ const selectSpy = jest.fn();
51
+ const TestComponent = jest
52
+ .fn()
53
+ .mockImplementation( getTestComponent( selectSpy, 'keyName' ) );
54
+ const testInstance = render(
55
+ <RegistryProvider value={ registry }>
56
+ <TestComponent keyName="foo" />
57
+ </RegistryProvider>
58
+ );
59
+ // 2 times expected
60
+ // - 1 for initial mount
61
+ // - 1 for after mount before subscription set.
62
+ expect( selectSpy ).toHaveBeenCalledTimes( 2 );
63
+ expect( TestComponent ).toHaveBeenCalledTimes( 2 );
64
+
65
+ // ensure expected state was rendered
66
+ expect( testInstance.findByText( 'bar' ) ).toBeTruthy();
67
+ } );
68
+
69
+ it( 'uses memoized selectors', () => {
70
+ const selectors = [];
71
+ const TestComponent = jest.fn().mockImplementation( ( props ) => {
72
+ useQuerySelect(
73
+ function ( query ) {
74
+ selectors.push( query( 'testStore' ) );
75
+ selectors.push( query( 'testStore' ) );
76
+ return null;
77
+ },
78
+ [ props.keyName ]
79
+ );
80
+ return <div />;
81
+ } );
82
+
83
+ render(
84
+ <RegistryProvider value={ registry }>
85
+ <TestComponent keyName="foo" />
86
+ </RegistryProvider>
87
+ );
88
+
89
+ // ensure the selectors were properly memoized
90
+ expect( selectors ).toHaveLength( 4 );
91
+ expect( selectors[ 0 ] ).toHaveProperty( 'testSelector' );
92
+ expect( selectors[ 0 ] ).toBe( selectors[ 1 ] );
93
+ expect( selectors[ 1 ] ).toBe( selectors[ 2 ] );
94
+
95
+ // Re-render
96
+ render(
97
+ <RegistryProvider value={ registry }>
98
+ <TestComponent keyName="bar" />
99
+ </RegistryProvider>
100
+ );
101
+
102
+ // ensure we still got the memoized results after re-rendering
103
+ expect( selectors ).toHaveLength( 8 );
104
+ expect( selectors[ 3 ] ).toHaveProperty( 'testSelector' );
105
+ expect( selectors[ 5 ] ).toBe( selectors[ 6 ] );
106
+ } );
107
+
108
+ it( 'returns the expected "response" details – no resolvers and arguments', () => {
109
+ let querySelectData;
110
+ const TestComponent = jest.fn().mockImplementation( () => {
111
+ querySelectData = useQuerySelect( function ( query ) {
112
+ return query( 'testStore' ).getFoo();
113
+ }, [] );
114
+ return <div />;
115
+ } );
116
+
117
+ render(
118
+ <RegistryProvider value={ registry }>
119
+ <TestComponent />
120
+ </RegistryProvider>
121
+ );
122
+
123
+ expect( querySelectData ).toEqual( {
124
+ data: 'bar',
125
+ isResolving: false,
126
+ hasResolved: false,
127
+ status: 'IDLE',
128
+ } );
129
+ } );
130
+
131
+ it( 'returns the expected "response" details – resolvers and arguments', async () => {
132
+ registry.register(
133
+ createReduxStore( 'resolverStore', {
134
+ reducer: ( state = { resolvedFoo: 0 }, action ) => {
135
+ if ( action?.type === 'RECEIVE_FOO' ) {
136
+ return { ...state, resolvedFoo: action.value };
137
+ }
138
+ return state;
139
+ },
140
+ actions: {
141
+ receiveFoo: ( value ) => ( {
142
+ type: 'RECEIVE_FOO',
143
+ value,
144
+ } ),
145
+ },
146
+ resolvers: {
147
+ getResolvedFoo: () => ( { dispatch } ) =>
148
+ dispatch.receiveFoo( 5 ),
149
+ },
150
+ selectors: {
151
+ getResolvedFoo: ( state, arg ) => state.resolvedFoo + arg,
152
+ },
153
+ } )
154
+ );
155
+
156
+ let querySelectData;
157
+ const TestComponent = jest.fn().mockImplementation( () => {
158
+ querySelectData = useQuerySelect( function ( query ) {
159
+ return query( 'resolverStore' ).getResolvedFoo( 10 );
160
+ }, [] );
161
+ return <div />;
162
+ } );
163
+
164
+ // Initial render, expect default values
165
+ render(
166
+ <RegistryProvider value={ registry }>
167
+ <TestComponent />
168
+ </RegistryProvider>
169
+ );
170
+ expect( querySelectData ).toEqual( {
171
+ data: 10,
172
+ isResolving: false,
173
+ hasResolved: false,
174
+ status: 'IDLE',
175
+ } );
176
+
177
+ await act( async () => {
178
+ jest.advanceTimersToNextTimer();
179
+ } );
180
+
181
+ // Re-render, expect resolved data
182
+ render(
183
+ <RegistryProvider value={ registry }>
184
+ <TestComponent />
185
+ </RegistryProvider>
186
+ );
187
+ expect( querySelectData ).toEqual( {
188
+ data: 15,
189
+ isResolving: false,
190
+ hasResolved: true,
191
+ status: 'SUCCESS',
192
+ } );
193
+ } );
194
+ } );
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import useQuerySelect from './use-query-select';
5
+ import { store as coreStore } from '../';
6
+ import { Status } from './constants';
7
+
8
+ interface EntityRecordResolution< RecordType > {
9
+ /** The requested entity record */
10
+ record: RecordType | null;
11
+
12
+ /**
13
+ * Is the record still being resolved?
14
+ */
15
+ isResolving: boolean;
16
+
17
+ /**
18
+ * Is the record resolved by now?
19
+ */
20
+ hasResolved: boolean;
21
+
22
+ /** Resolution status */
23
+ status: Status;
24
+ }
25
+
26
+ /**
27
+ * Resolves the specified entity record.
28
+ *
29
+ * @param kind Kind of the requested entity.
30
+ * @param name Name of the requested entity.
31
+ * @param recordId Record ID of the requested entity.
32
+ *
33
+ * @example
34
+ * ```js
35
+ * import { useEntityRecord } from '@wordpress/core-data';
36
+ *
37
+ * function PageTitleDisplay( { id } ) {
38
+ * const { record, isResolving } = useEntityRecord( 'postType', 'page', id );
39
+ *
40
+ * if ( isResolving ) {
41
+ * return 'Loading...';
42
+ * }
43
+ *
44
+ * return record.title;
45
+ * }
46
+ *
47
+ * // Rendered in the application:
48
+ * // <PageTitleDisplay id={ 1 } />
49
+ * ```
50
+ *
51
+ * In the above example, when `PageTitleDisplay` is rendered into an
52
+ * application, the page and the resolution details will be retrieved from
53
+ * the store state using `getEntityRecord()`, or resolved if missing.
54
+ *
55
+ * @return {EntityRecordResolution<RecordType>} Entity record data.
56
+ * @template RecordType
57
+ */
58
+ export default function __experimentalUseEntityRecord< RecordType >(
59
+ kind: string,
60
+ name: string,
61
+ recordId: string | number
62
+ ): EntityRecordResolution< RecordType > {
63
+ const { data: record, ...rest } = useQuerySelect(
64
+ ( query ) => query( coreStore ).getEntityRecord( kind, name, recordId ),
65
+ [ kind, name, recordId ]
66
+ );
67
+
68
+ return {
69
+ record,
70
+ ...rest,
71
+ };
72
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import useQuerySelect from './use-query-select';
5
+ import { store as coreStore } from '../';
6
+ import { Status } from './constants';
7
+
8
+ interface EntityRecordsResolution< RecordType > {
9
+ /** The requested entity record */
10
+ records: RecordType[] | null;
11
+
12
+ /**
13
+ * Is the record still being resolved?
14
+ */
15
+ isResolving: boolean;
16
+
17
+ /**
18
+ * Is the record resolved by now?
19
+ */
20
+ hasResolved: boolean;
21
+
22
+ /** Resolution status */
23
+ status: Status;
24
+ }
25
+
26
+ /**
27
+ * Resolves the specified entity records.
28
+ *
29
+ * @param kind Kind of the requested entities.
30
+ * @param name Name of the requested entities.
31
+ * @param queryArgs HTTP query for the requested entities.
32
+ *
33
+ * @example
34
+ * ```js
35
+ * import { useEntityRecord } from '@wordpress/core-data';
36
+ *
37
+ * function PageTitlesList() {
38
+ * const { records, isResolving } = useEntityRecords( 'postType', 'page' );
39
+ *
40
+ * if ( isResolving ) {
41
+ * return 'Loading...';
42
+ * }
43
+ *
44
+ * return (
45
+ * <ul>
46
+ * {records.map(( page ) => (
47
+ * <li>{ page.title }</li>
48
+ * ))}
49
+ * </ul>
50
+ * );
51
+ * }
52
+ *
53
+ * // Rendered in the application:
54
+ * // <PageTitlesList />
55
+ * ```
56
+ *
57
+ * In the above example, when `PageTitlesList` is rendered into an
58
+ * application, the list of records and the resolution details will be retrieved from
59
+ * the store state using `getEntityRecords()`, or resolved if missing.
60
+ *
61
+ * @return {EntityRecordsResolution<RecordType>} Entity records data.
62
+ * @template RecordType
63
+ */
64
+ export default function __experimentalUseEntityRecords< RecordType >(
65
+ kind: string,
66
+ name: string,
67
+ queryArgs: unknown = {}
68
+ ): EntityRecordsResolution< RecordType > {
69
+ const { data: records, ...rest } = useQuerySelect(
70
+ ( query ) =>
71
+ query( coreStore ).getEntityRecords( kind, name, queryArgs ),
72
+ [ kind, name, queryArgs ]
73
+ );
74
+
75
+ return {
76
+ records,
77
+ ...rest,
78
+ };
79
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect } from '@wordpress/data';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import memoize from './memoize';
10
+ import { Status } from './constants';
11
+
12
+ export const META_SELECTORS = [
13
+ 'getIsResolving',
14
+ 'hasStartedResolution',
15
+ 'hasFinishedResolution',
16
+ 'isResolving',
17
+ 'getCachedResolvers',
18
+ ];
19
+
20
+ interface QuerySelectResponse {
21
+ /** the requested selector return value */
22
+ data: Object;
23
+
24
+ /** is the record still being resolved? Via the `getIsResolving` meta-selector */
25
+ isResolving: boolean;
26
+
27
+ /** was the resolution started? Via the `hasStartedResolution` meta-selector */
28
+ hasStarted: boolean;
29
+
30
+ /** has the resolution finished? Via the `hasFinishedResolution` meta-selector. */
31
+ hasResolved: boolean;
32
+ }
33
+
34
+ /**
35
+ * Like useSelect, but the selectors return objects containing
36
+ * both the original data AND the resolution info.
37
+ *
38
+ * @param {Function} mapQuerySelect see useSelect
39
+ * @param {Array} deps see useSelect
40
+ *
41
+ * @example
42
+ * ```js
43
+ * import { useQuerySelect } from '@wordpress/data';
44
+ * import { store as coreDataStore } from '@wordpress/core-data';
45
+ *
46
+ * function PageTitleDisplay( { id } ) {
47
+ * const { data: page, isResolving } = useQuerySelect( ( query ) => {
48
+ * return query( coreDataStore ).getEntityRecord( 'postType', 'page', id )
49
+ * }, [ id ] );
50
+ *
51
+ * if ( isResolving ) {
52
+ * return 'Loading...';
53
+ * }
54
+ *
55
+ * return page.title;
56
+ * }
57
+ *
58
+ * // Rendered in the application:
59
+ * // <PageTitleDisplay id={ 10 } />
60
+ * ```
61
+ *
62
+ * In the above example, when `PageTitleDisplay` is rendered into an
63
+ * application, the page and the resolution details will be retrieved from
64
+ * the store state using the `mapSelect` callback on `useQuerySelect`.
65
+ *
66
+ * If the id prop changes then any page in the state for that id is
67
+ * retrieved. If the id prop doesn't change and other props are passed in
68
+ * that do change, the title will not change because the dependency is just
69
+ * the id.
70
+ * @see useSelect
71
+ *
72
+ * @return {QuerySelectResponse} Queried data.
73
+ */
74
+ export default function __experimentalUseQuerySelect( mapQuerySelect, deps ) {
75
+ return useSelect( ( select, registry ) => {
76
+ const resolve = ( store ) => enrichSelectors( select( store ) );
77
+ return mapQuerySelect( resolve, registry );
78
+ }, deps );
79
+ }
80
+
81
+ type QuerySelector = ( ...args ) => QuerySelectResponse;
82
+ interface EnrichedSelectors {
83
+ [ key: string ]: QuerySelector;
84
+ }
85
+
86
+ /**
87
+ * Transform simple selectors into ones that return an object with the
88
+ * original return value AND the resolution info.
89
+ *
90
+ * @param {Object} selectors Selectors to enrich
91
+ * @return {EnrichedSelectors} Enriched selectors
92
+ */
93
+ const enrichSelectors = memoize( ( selectors ) => {
94
+ const resolvers = {};
95
+ for ( const selectorName in selectors ) {
96
+ if ( META_SELECTORS.includes( selectorName ) ) {
97
+ continue;
98
+ }
99
+ Object.defineProperty( resolvers, selectorName, {
100
+ get: () => ( ...args ) => {
101
+ const { getIsResolving, hasFinishedResolution } = selectors;
102
+ const isResolving = !! getIsResolving( selectorName, args );
103
+ const hasResolved =
104
+ ! isResolving &&
105
+ hasFinishedResolution( selectorName, args );
106
+ const data = selectors[ selectorName ]( ...args );
107
+
108
+ let status;
109
+ if ( isResolving ) {
110
+ status = Status.Resolving;
111
+ } else if ( hasResolved ) {
112
+ if ( data ) {
113
+ status = Status.Success;
114
+ } else {
115
+ status = Status.Error;
116
+ }
117
+ } else {
118
+ status = Status.Idle;
119
+ }
120
+
121
+ return {
122
+ data,
123
+ status,
124
+ isResolving,
125
+ hasResolved,
126
+ };
127
+ },
128
+ } );
129
+ }
130
+ return resolvers;
131
+ } );
package/src/index.js CHANGED
@@ -59,7 +59,6 @@ const storeConfig = () => ( {
59
59
  actions: { ...actions, ...entityActions, ...createLocksActions() },
60
60
  selectors: { ...selectors, ...entitySelectors },
61
61
  resolvers: { ...resolvers, ...entityResolvers },
62
- __experimentalUseThunks: true,
63
62
  } );
64
63
 
65
64
  /**
@@ -74,5 +73,8 @@ export const store = createReduxStore( STORE_NAME, storeConfig() );
74
73
  register( store );
75
74
 
76
75
  export { default as EntityProvider } from './entity-provider';
76
+ export { default as __experimentalUseEntityRecord } from './hooks/use-entity-record';
77
+ export { default as __experimentalUseEntityRecords } from './hooks/use-entity-records';
77
78
  export * from './entity-provider';
78
79
  export * from './fetch';
80
+ export * from './types';
package/src/resolvers.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { find, includes, get, hasIn, compact, uniq } from 'lodash';
4
+ import { find, includes, get, compact, uniq } from 'lodash';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
@@ -283,11 +283,7 @@ export const canUser = ( action, resource, id ) => async ( { dispatch } ) => {
283
283
  try {
284
284
  response = await apiFetch( {
285
285
  path,
286
- // Ideally this would always be an OPTIONS request, but unfortunately there's
287
- // a bug in the REST API which causes the Allow header to not be sent on
288
- // OPTIONS requests to /posts/:id routes.
289
- // https://core.trac.wordpress.org/ticket/45753
290
- method: id ? 'GET' : 'OPTIONS',
286
+ method: 'OPTIONS',
291
287
  parse: false,
292
288
  } );
293
289
  } catch ( error ) {
@@ -296,17 +292,7 @@ export const canUser = ( action, resource, id ) => async ( { dispatch } ) => {
296
292
  return;
297
293
  }
298
294
 
299
- let allowHeader;
300
- if ( hasIn( response, [ 'headers', 'get' ] ) ) {
301
- // If the request is fetched using the fetch api, the header can be
302
- // retrieved using the 'get' method.
303
- allowHeader = response.headers.get( 'allow' );
304
- } else {
305
- // If the request was preloaded server-side and is returned by the
306
- // preloading middleware, the header will be a simple property.
307
- allowHeader = get( response, [ 'headers', 'Allow' ], '' );
308
- }
309
-
295
+ const allowHeader = response.headers.get( 'allow' );
310
296
  const key = compact( [ action, resource, id ] ).join( '/' );
311
297
  const isAllowed = includes( allowHeader, method );
312
298
  dispatch.receiveUserPermission( key, isAllowed );
@@ -312,9 +312,7 @@ describe( 'canUser', () => {
312
312
  } );
313
313
 
314
314
  triggerFetch.mockImplementation( () => ( {
315
- headers: {
316
- Allow: 'GET',
317
- },
315
+ headers: new Map( [ [ 'allow', 'GET' ] ] ),
318
316
  } ) );
319
317
 
320
318
  await canUser( 'create', 'media' )( { dispatch } );
@@ -337,9 +335,7 @@ describe( 'canUser', () => {
337
335
  } );
338
336
 
339
337
  triggerFetch.mockImplementation( () => ( {
340
- headers: {
341
- Allow: 'POST, GET, PUT, DELETE',
342
- },
338
+ headers: new Map( [ [ 'allow', 'POST, GET, PUT, DELETE' ] ] ),
343
339
  } ) );
344
340
 
345
341
  await canUser( 'create', 'media' )( { dispatch } );
@@ -362,16 +358,14 @@ describe( 'canUser', () => {
362
358
  } );
363
359
 
364
360
  triggerFetch.mockImplementation( () => ( {
365
- headers: {
366
- Allow: 'POST, GET, PUT, DELETE',
367
- },
361
+ headers: new Map( [ [ 'allow', 'POST, GET, PUT, DELETE' ] ] ),
368
362
  } ) );
369
363
 
370
364
  await canUser( 'create', 'blocks', 123 )( { dispatch } );
371
365
 
372
366
  expect( triggerFetch ).toHaveBeenCalledWith( {
373
367
  path: '/wp/v2/blocks/123',
374
- method: 'GET',
368
+ method: 'OPTIONS',
375
369
  parse: false,
376
370
  } );
377
371