@wordpress/core-data 4.2.1 → 4.4.1

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 (147) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +68 -11
  3. package/build/actions.js +61 -41
  4. package/build/actions.js.map +1 -1
  5. package/build/batch/default-processor.js +1 -1
  6. package/build/batch/default-processor.js.map +1 -1
  7. package/build/entities.js +36 -23
  8. package/build/entities.js.map +1 -1
  9. package/build/entity-provider.js +46 -44
  10. package/build/entity-provider.js.map +1 -1
  11. package/build/entity-types/{base-entity-types.js → base-entity-records.js} +9 -9
  12. package/build/entity-types/base-entity-records.js.map +1 -0
  13. package/build/fetch/__experimental-fetch-link-suggestions.js +48 -11
  14. package/build/fetch/__experimental-fetch-link-suggestions.js.map +1 -1
  15. package/build/fetch/__experimental-fetch-url-data.js +1 -1
  16. package/build/fetch/__experimental-fetch-url-data.js.map +1 -1
  17. package/build/hooks/use-entity-record.js +15 -5
  18. package/build/hooks/use-entity-record.js.map +1 -1
  19. package/build/hooks/use-entity-records.js +14 -2
  20. package/build/hooks/use-entity-records.js.map +1 -1
  21. package/build/hooks/use-query-select.js.map +1 -1
  22. package/build/index.js +9 -21
  23. package/build/index.js.map +1 -1
  24. package/build/queried-data/actions.js +4 -4
  25. package/build/queried-data/actions.js.map +1 -1
  26. package/build/queried-data/get-query-parts.js +7 -3
  27. package/build/queried-data/get-query-parts.js.map +1 -1
  28. package/build/queried-data/reducer.js +8 -6
  29. package/build/queried-data/reducer.js.map +1 -1
  30. package/build/reducer.js +77 -25
  31. package/build/reducer.js.map +1 -1
  32. package/build/resolvers.js +60 -24
  33. package/build/resolvers.js.map +1 -1
  34. package/build/selectors.js +122 -55
  35. package/build/selectors.js.map +1 -1
  36. package/build/types.js +6 -0
  37. package/build/types.js.map +1 -0
  38. package/build/utils/conservative-map-item.js +1 -1
  39. package/build/utils/conservative-map-item.js.map +1 -1
  40. package/build/utils/if-matching-action.js +4 -2
  41. package/build/utils/if-matching-action.js.map +1 -1
  42. package/build/utils/is-raw-attribute.js +1 -1
  43. package/build/utils/is-raw-attribute.js.map +1 -1
  44. package/build/utils/on-sub-key.js +3 -1
  45. package/build/utils/on-sub-key.js.map +1 -1
  46. package/build/utils/replace-action.js +4 -2
  47. package/build/utils/replace-action.js.map +1 -1
  48. package/build-module/actions.js +62 -42
  49. package/build-module/actions.js.map +1 -1
  50. package/build-module/batch/default-processor.js +1 -1
  51. package/build-module/batch/default-processor.js.map +1 -1
  52. package/build-module/entities.js +32 -19
  53. package/build-module/entities.js.map +1 -1
  54. package/build-module/entity-provider.js +47 -45
  55. package/build-module/entity-provider.js.map +1 -1
  56. package/build-module/entity-types/{base-entity-types.js → base-entity-records.js} +7 -7
  57. package/build-module/entity-types/base-entity-records.js.map +1 -0
  58. package/build-module/fetch/__experimental-fetch-link-suggestions.js +48 -11
  59. package/build-module/fetch/__experimental-fetch-link-suggestions.js.map +1 -1
  60. package/build-module/fetch/__experimental-fetch-url-data.js +1 -1
  61. package/build-module/fetch/__experimental-fetch-url-data.js.map +1 -1
  62. package/build-module/hooks/use-entity-record.js +15 -5
  63. package/build-module/hooks/use-entity-record.js.map +1 -1
  64. package/build-module/hooks/use-entity-records.js +14 -2
  65. package/build-module/hooks/use-entity-records.js.map +1 -1
  66. package/build-module/hooks/use-query-select.js.map +1 -1
  67. package/build-module/index.js +10 -22
  68. package/build-module/index.js.map +1 -1
  69. package/build-module/queried-data/actions.js +4 -4
  70. package/build-module/queried-data/actions.js.map +1 -1
  71. package/build-module/queried-data/get-query-parts.js +7 -3
  72. package/build-module/queried-data/get-query-parts.js.map +1 -1
  73. package/build-module/queried-data/reducer.js +8 -6
  74. package/build-module/queried-data/reducer.js.map +1 -1
  75. package/build-module/reducer.js +75 -26
  76. package/build-module/reducer.js.map +1 -1
  77. package/build-module/resolvers.js +55 -25
  78. package/build-module/resolvers.js.map +1 -1
  79. package/build-module/selectors.js +114 -55
  80. package/build-module/selectors.js.map +1 -1
  81. package/build-module/types.js +2 -0
  82. package/build-module/types.js.map +1 -0
  83. package/build-module/utils/conservative-map-item.js +1 -1
  84. package/build-module/utils/conservative-map-item.js.map +1 -1
  85. package/build-module/utils/if-matching-action.js +4 -2
  86. package/build-module/utils/if-matching-action.js.map +1 -1
  87. package/build-module/utils/is-raw-attribute.js +1 -1
  88. package/build-module/utils/is-raw-attribute.js.map +1 -1
  89. package/build-module/utils/on-sub-key.js +3 -1
  90. package/build-module/utils/on-sub-key.js.map +1 -1
  91. package/build-module/utils/replace-action.js +4 -2
  92. package/build-module/utils/replace-action.js.map +1 -1
  93. package/package.json +11 -11
  94. package/src/actions.js +62 -42
  95. package/src/batch/default-processor.js +1 -0
  96. package/src/{entities.js → entities.ts} +50 -21
  97. package/src/entity-provider.js +50 -44
  98. package/src/entity-types/attachment.ts +5 -5
  99. package/src/entity-types/{base-entity-types.ts → base-entity-records.ts} +5 -5
  100. package/src/entity-types/comment.ts +5 -5
  101. package/src/entity-types/helpers.ts +1 -1
  102. package/src/entity-types/index.ts +4 -4
  103. package/src/entity-types/menu-location.ts +5 -5
  104. package/src/entity-types/nav-menu-item.ts +10 -5
  105. package/src/entity-types/nav-menu.ts +5 -5
  106. package/src/entity-types/navigation-area.ts +5 -5
  107. package/src/entity-types/page.ts +5 -5
  108. package/src/entity-types/plugin.ts +10 -5
  109. package/src/entity-types/post.ts +5 -5
  110. package/src/entity-types/settings.ts +10 -5
  111. package/src/entity-types/sidebar.ts +6 -7
  112. package/src/entity-types/taxonomy.ts +5 -5
  113. package/src/entity-types/theme.ts +5 -5
  114. package/src/entity-types/type.ts +5 -5
  115. package/src/entity-types/user.ts +10 -5
  116. package/src/entity-types/widget-type.ts +5 -5
  117. package/src/entity-types/widget.ts +5 -5
  118. package/src/entity-types/wp-template-part.ts +5 -5
  119. package/src/entity-types/wp-template.ts +5 -5
  120. package/src/fetch/__experimental-fetch-link-suggestions.js +56 -20
  121. package/src/fetch/__experimental-fetch-url-data.js +1 -0
  122. package/src/fetch/test/__experimental-fetch-link-suggestions.js +39 -1
  123. package/src/hooks/use-entity-record.ts +19 -8
  124. package/src/hooks/use-entity-records.ts +23 -6
  125. package/src/hooks/use-query-select.ts +12 -7
  126. package/src/index.js +10 -15
  127. package/src/locks/test/selectors.js +4 -4
  128. package/src/queried-data/actions.js +4 -4
  129. package/src/queried-data/get-query-parts.js +5 -5
  130. package/src/queried-data/reducer.js +6 -6
  131. package/src/reducer.js +67 -24
  132. package/src/resolvers.js +52 -31
  133. package/src/{selectors.js → selectors.ts} +118 -57
  134. package/src/test/actions.js +138 -33
  135. package/src/test/entities.js +11 -11
  136. package/src/test/reducer.js +4 -4
  137. package/src/test/resolvers.js +5 -5
  138. package/src/test/selectors.js +22 -22
  139. package/src/types.ts +3 -0
  140. package/src/utils/conservative-map-item.js +1 -1
  141. package/src/utils/if-matching-action.js +4 -2
  142. package/src/utils/is-raw-attribute.js +1 -1
  143. package/src/utils/on-sub-key.js +3 -1
  144. package/src/utils/replace-action.js +4 -2
  145. package/src/utils/test/is-raw-attribute.js +4 -4
  146. package/build/entity-types/base-entity-types.js.map +0 -1
  147. package/build-module/entity-types/base-entity-types.js.map +0 -1
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { Context, ContextualField, OmitNevers } from './helpers';
4
+ import type { Context, ContextualField, OmitNevers } from './helpers';
5
5
 
6
- import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types';
6
+ import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records';
7
7
 
8
- declare module './base-entity-types' {
9
- export namespace BaseEntityTypes {
8
+ declare module './base-entity-records' {
9
+ export namespace BaseEntityRecords {
10
10
  export interface Type< C extends Context > {
11
11
  /**
12
12
  * All capabilities used by the post type.
@@ -76,5 +76,5 @@ declare module './base-entity-types' {
76
76
  }
77
77
 
78
78
  export type Type< C extends Context > = OmitNevers<
79
- _BaseEntityTypes.Type< C >
79
+ _BaseEntityRecords.Type< C >
80
80
  >;
@@ -1,12 +1,17 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { AvatarUrls, Context, ContextualField, OmitNevers } from './helpers';
4
+ import type {
5
+ AvatarUrls,
6
+ Context,
7
+ ContextualField,
8
+ OmitNevers,
9
+ } from './helpers';
5
10
 
6
- import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types';
11
+ import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records';
7
12
 
8
- declare module './base-entity-types' {
9
- export namespace BaseEntityTypes {
13
+ declare module './base-entity-records' {
14
+ export namespace BaseEntityRecords {
10
15
  export interface User< C extends Context > {
11
16
  /**
12
17
  * Unique identifier for the user.
@@ -105,5 +110,5 @@ declare module './base-entity-types' {
105
110
  }
106
111
 
107
112
  export type User< C extends Context > = OmitNevers<
108
- _BaseEntityTypes.User< C >
113
+ _BaseEntityRecords.User< C >
109
114
  >;
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { Context, OmitNevers } from './helpers';
4
+ import type { Context, OmitNevers } from './helpers';
5
5
 
6
- import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types';
6
+ import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records';
7
7
 
8
- declare module './base-entity-types' {
9
- export namespace BaseEntityTypes {
8
+ declare module './base-entity-records' {
9
+ export namespace BaseEntityRecords {
10
10
  export interface WidgetType< C extends Context > {
11
11
  /**
12
12
  * Unique slug identifying the widget type.
@@ -33,5 +33,5 @@ declare module './base-entity-types' {
33
33
  }
34
34
 
35
35
  export type WidgetType< C extends Context > = OmitNevers<
36
- _BaseEntityTypes.WidgetType< C >
36
+ _BaseEntityRecords.WidgetType< C >
37
37
  >;
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { Context, ContextualField, OmitNevers } from './helpers';
4
+ import type { Context, ContextualField, OmitNevers } from './helpers';
5
5
 
6
- import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types';
6
+ import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records';
7
7
 
8
- declare module './base-entity-types' {
9
- export namespace BaseEntityTypes {
8
+ declare module './base-entity-records' {
9
+ export namespace BaseEntityRecords {
10
10
  export interface Widget< C extends Context > {
11
11
  /**
12
12
  * Unique identifier for the widget.
@@ -60,5 +60,5 @@ declare module './base-entity-types' {
60
60
  }
61
61
 
62
62
  export type Widget< C extends Context > = OmitNevers<
63
- _BaseEntityTypes.Widget< C >
63
+ _BaseEntityRecords.Widget< C >
64
64
  >;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import {
4
+ import type {
5
5
  Context,
6
6
  PostStatus,
7
7
  RenderedText,
@@ -9,10 +9,10 @@ import {
9
9
  ContextualField,
10
10
  } from './helpers';
11
11
 
12
- import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types';
12
+ import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records';
13
13
 
14
- declare module './base-entity-types' {
15
- export namespace BaseEntityTypes {
14
+ declare module './base-entity-records' {
15
+ export namespace BaseEntityRecords {
16
16
  export interface WpTemplatePart< C extends Context > {
17
17
  /**
18
18
  * ID of template.
@@ -90,5 +90,5 @@ declare module './base-entity-types' {
90
90
  }
91
91
 
92
92
  export type WpTemplatePart< C extends Context > = OmitNevers<
93
- _BaseEntityTypes.WpTemplatePart< C >
93
+ _BaseEntityRecords.WpTemplatePart< C >
94
94
  >;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import {
4
+ import type {
5
5
  Context,
6
6
  PostStatus,
7
7
  RenderedText,
@@ -9,10 +9,10 @@ import {
9
9
  ContextualField,
10
10
  } from './helpers';
11
11
 
12
- import { BaseEntityTypes as _BaseEntityTypes } from './base-entity-types';
12
+ import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records';
13
13
 
14
- declare module './base-entity-types' {
15
- export namespace BaseEntityTypes {
14
+ declare module './base-entity-records' {
15
+ export namespace BaseEntityRecords {
16
16
  export interface WpTemplate< C extends Context > {
17
17
  /**
18
18
  * ID of template.
@@ -90,5 +90,5 @@ declare module './base-entity-types' {
90
90
  }
91
91
 
92
92
  export type WpTemplate< C extends Context > = OmitNevers<
93
- _BaseEntityTypes.WpTemplate< C >
93
+ _BaseEntityRecords.WpTemplate< C >
94
94
  >;
@@ -9,7 +9,7 @@ import { __ } from '@wordpress/i18n';
9
9
  /**
10
10
  * Filters the search by type
11
11
  *
12
- * @typedef { 'post' | 'term' | 'post-format' } WPLinkSearchType
12
+ * @typedef { 'attachment' | 'post' | 'term' | 'post-format' } WPLinkSearchType
13
13
  */
14
14
 
15
15
  /**
@@ -38,6 +38,17 @@ import { __ } from '@wordpress/i18n';
38
38
  * @property {WPKind} [kind] Link kind of post-type or taxonomy
39
39
  */
40
40
 
41
+ /**
42
+ * @typedef WPLinkSearchResultAugments
43
+ *
44
+ * @property {{kind: WPKind}} [meta] Contains kind information.
45
+ * @property {WPKind} [subtype] Optional subtype if it exists.
46
+ */
47
+
48
+ /**
49
+ * @typedef {WPLinkSearchResult & WPLinkSearchResultAugments} WPLinkSearchResultAugmented
50
+ */
51
+
41
52
  /**
42
53
  * @typedef WPEditorSettings
43
54
  *
@@ -82,6 +93,7 @@ const fetchLinkSuggestions = async (
82
93
 
83
94
  const { disablePostFormats = false } = settings;
84
95
 
96
+ /** @type {Promise<WPLinkSearchResult>[]} */
85
97
  const queries = [];
86
98
 
87
99
  if ( ! type || type === 'post' ) {
@@ -126,7 +138,7 @@ const fetchLinkSuggestions = async (
126
138
  };
127
139
  } );
128
140
  } )
129
- .catch( () => [] )
141
+ .catch( () => [] ) // Fail by returning no results.
130
142
  );
131
143
  }
132
144
 
@@ -149,14 +161,36 @@ const fetchLinkSuggestions = async (
149
161
  };
150
162
  } );
151
163
  } )
152
- .catch( () => [] )
164
+ .catch( () => [] ) // Fail by returning no results.
165
+ );
166
+ }
167
+
168
+ if ( ! type || type === 'attachment' ) {
169
+ queries.push(
170
+ apiFetch( {
171
+ path: addQueryArgs( '/wp/v2/media', {
172
+ search,
173
+ page,
174
+ per_page: perPage,
175
+ } ),
176
+ } )
177
+ .then( ( results ) => {
178
+ return results.map( ( result ) => {
179
+ return {
180
+ ...result,
181
+ meta: { kind: 'media' },
182
+ };
183
+ } );
184
+ } )
185
+ .catch( () => [] ) // Fail by returning no results.
153
186
  );
154
187
  }
155
188
 
156
189
  return Promise.all( queries ).then( ( results ) => {
157
190
  return results
158
191
  .reduce(
159
- ( accumulator, current ) => accumulator.concat( current ), // Flatten list.
192
+ ( /** @type {WPLinkSearchResult[]} */ accumulator, current ) =>
193
+ accumulator.concat( current ), // Flatten list.
160
194
  []
161
195
  )
162
196
  .filter(
@@ -168,22 +202,24 @@ const fetchLinkSuggestions = async (
168
202
  }
169
203
  )
170
204
  .slice( 0, perPage )
171
- .map(
172
- /**
173
- * @param {{ id: number, url:string, title?:string, subtype?: string, type?: string }} result
174
- */
175
- ( result ) => {
176
- return {
177
- id: result.id,
178
- url: result.url,
179
- title:
180
- decodeEntities( result.title || '' ) ||
181
- __( '(no title)' ),
182
- type: result.subtype || result.type,
183
- kind: result?.meta?.kind,
184
- };
185
- }
186
- );
205
+ .map( ( /** @type {WPLinkSearchResultAugmented} */ result ) => {
206
+ const isMedia = result.type === 'attachment';
207
+
208
+ return {
209
+ id: result.id,
210
+ // @ts-ignore fix when we make this a TS file
211
+ url: isMedia ? result.source_url : result.url,
212
+ title:
213
+ decodeEntities(
214
+ isMedia
215
+ ? // @ts-ignore fix when we make this a TS file
216
+ result.title.rendered
217
+ : result.title || ''
218
+ ) || __( '(no title)' ),
219
+ type: result.subtype || result.type,
220
+ kind: result?.meta?.kind,
221
+ };
222
+ } );
187
223
  } );
188
224
  };
189
225
 
@@ -60,6 +60,7 @@ const fetchUrlData = async ( url, options = {} ) => {
60
60
  const protocol = getProtocol( url );
61
61
 
62
62
  if (
63
+ ! protocol ||
63
64
  ! isValidProtocol( protocol ) ||
64
65
  ! protocol.startsWith( 'http' ) ||
65
66
  ! /^https?:\/\/[^\/\s]/i.test( url )
@@ -70,6 +70,18 @@ jest.mock( '@wordpress/api-fetch', () =>
70
70
  subtype: 'page',
71
71
  },
72
72
  ] );
73
+ case '/wp/v2/media?search=&per_page=20':
74
+ return Promise.resolve( [
75
+ {
76
+ id: 54,
77
+ title: {
78
+ rendered: 'Some Test Media Title',
79
+ },
80
+ type: 'attachment',
81
+ source_url:
82
+ 'http://localhost:8888/wp-content/uploads/2022/03/test-pdf.pdf',
83
+ },
84
+ ] );
73
85
  default:
74
86
  return Promise.resolve( [
75
87
  {
@@ -154,7 +166,25 @@ describe( 'fetchLinkSuggestions', () => {
154
166
  { disablePostFormats: true }
155
167
  ).then( ( suggestions ) => expect( suggestions ).toEqual( [] ) );
156
168
  } );
157
- it( 'returns suggestions from post, term, and post-format', () => {
169
+
170
+ it( 'filters suggestions by attachment', () => {
171
+ return fetchLinkSuggestions( '', {
172
+ type: 'attachment',
173
+ } ).then( ( suggestions ) =>
174
+ expect( suggestions ).toEqual( [
175
+ {
176
+ id: 54,
177
+ title: 'Some Test Media Title',
178
+ url:
179
+ 'http://localhost:8888/wp-content/uploads/2022/03/test-pdf.pdf',
180
+ type: 'attachment',
181
+ kind: 'media',
182
+ },
183
+ ] )
184
+ );
185
+ } );
186
+
187
+ it( 'returns suggestions from post, term, post-format and media', () => {
158
188
  return fetchLinkSuggestions( '', {} ).then( ( suggestions ) =>
159
189
  expect( suggestions ).toEqual( [
160
190
  {
@@ -192,6 +222,14 @@ describe( 'fetchLinkSuggestions', () => {
192
222
  type: 'post-format',
193
223
  kind: 'taxonomy',
194
224
  },
225
+ {
226
+ id: 54,
227
+ title: 'Some Test Media Title',
228
+ url:
229
+ 'http://localhost:8888/wp-content/uploads/2022/03/test-pdf.pdf',
230
+ type: 'attachment',
231
+ kind: 'media',
232
+ },
195
233
  ] )
196
234
  );
197
235
  } );
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import useQuerySelect from './use-query-select';
5
5
  import { store as coreStore } from '../';
6
- import { Status } from './constants';
6
+ import type { Status } from './constants';
7
7
 
8
8
  interface EntityRecordResolution< RecordType > {
9
9
  /** The requested entity record */
@@ -23,13 +23,18 @@ interface EntityRecordResolution< RecordType > {
23
23
  status: Status;
24
24
  }
25
25
 
26
+ interface Options {
27
+ enabled: boolean;
28
+ }
29
+
26
30
  /**
27
31
  * Resolves the specified entity record.
28
32
  *
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
+ * @param kind Kind of the requested entity.
34
+ * @param name Name of the requested entity.
35
+ * @param recordId Record ID of the requested entity.
36
+ * @param options Hook options.
37
+ * @param [options.enabled=true] Whether to run the query or short-circuit and return null. Defaults to true.
33
38
  * @example
34
39
  * ```js
35
40
  * import { useEntityRecord } from '@wordpress/core-data';
@@ -58,11 +63,17 @@ interface EntityRecordResolution< RecordType > {
58
63
  export default function __experimentalUseEntityRecord< RecordType >(
59
64
  kind: string,
60
65
  name: string,
61
- recordId: string | number
66
+ recordId: string | number,
67
+ options: Options = { enabled: true }
62
68
  ): EntityRecordResolution< RecordType > {
63
69
  const { data: record, ...rest } = useQuerySelect(
64
- ( query ) => query( coreStore ).getEntityRecord( kind, name, recordId ),
65
- [ kind, name, recordId ]
70
+ ( query ) => {
71
+ if ( ! options.enabled ) {
72
+ return null;
73
+ }
74
+ return query( coreStore ).getEntityRecord( kind, name, recordId );
75
+ },
76
+ [ kind, name, recordId, options.enabled ]
66
77
  );
67
78
 
68
79
  return {
@@ -8,7 +8,7 @@ import { addQueryArgs } from '@wordpress/url';
8
8
  */
9
9
  import useQuerySelect from './use-query-select';
10
10
  import { store as coreStore } from '../';
11
- import { Status } from './constants';
11
+ import type { Status } from './constants';
12
12
 
13
13
  interface EntityRecordsResolution< RecordType > {
14
14
  /** The requested entity record */
@@ -28,12 +28,22 @@ interface EntityRecordsResolution< RecordType > {
28
28
  status: Status;
29
29
  }
30
30
 
31
+ interface Options {
32
+ /**
33
+ * Whether to run the query or short-circuit and return null.
34
+ *
35
+ * @default true
36
+ */
37
+ enabled: boolean;
38
+ }
39
+
31
40
  /**
32
41
  * Resolves the specified entity records.
33
42
  *
34
43
  * @param kind Kind of the requested entities.
35
44
  * @param name Name of the requested entities.
36
45
  * @param queryArgs HTTP query for the requested entities.
46
+ * @param options Hook options.
37
47
  * @example
38
48
  * ```js
39
49
  * import { useEntityRecord } from '@wordpress/core-data';
@@ -62,13 +72,14 @@ interface EntityRecordsResolution< RecordType > {
62
72
  * application, the list of records and the resolution details will be retrieved from
63
73
  * the store state using `getEntityRecords()`, or resolved if missing.
64
74
  *
65
- * @return {EntityRecordsResolution<RecordType>} Entity records data.
75
+ * @return Entity records data.
66
76
  * @template RecordType
67
77
  */
68
78
  export default function __experimentalUseEntityRecords< RecordType >(
69
79
  kind: string,
70
80
  name: string,
71
- queryArgs: unknown = {}
81
+ queryArgs: Record< string, unknown > = {},
82
+ options: Options = { enabled: true }
72
83
  ): EntityRecordsResolution< RecordType > {
73
84
  // Serialize queryArgs to a string that can be safely used as a React dep.
74
85
  // We can't just pass queryArgs as one of the deps, because if it is passed
@@ -77,9 +88,15 @@ export default function __experimentalUseEntityRecords< RecordType >(
77
88
  const queryAsString = addQueryArgs( '', queryArgs );
78
89
 
79
90
  const { data: records, ...rest } = useQuerySelect(
80
- ( query ) =>
81
- query( coreStore ).getEntityRecords( kind, name, queryArgs ),
82
- [ kind, name, queryAsString ]
91
+ ( query ) => {
92
+ if ( ! options.enabled ) {
93
+ return {
94
+ data: [],
95
+ };
96
+ }
97
+ return query( coreStore ).getEntityRecords( kind, name, queryArgs );
98
+ },
99
+ [ kind, name, queryAsString, options.enabled ]
83
100
  );
84
101
 
85
102
  return {
@@ -17,9 +17,9 @@ export const META_SELECTORS = [
17
17
  'getCachedResolvers',
18
18
  ];
19
19
 
20
- interface QuerySelectResponse {
20
+ interface QuerySelectResponse< Data > {
21
21
  /** the requested selector return value */
22
- data: Object;
22
+ data: Data;
23
23
 
24
24
  /** is the record still being resolved? Via the `getIsResolving` meta-selector */
25
25
  isResolving: boolean;
@@ -78,9 +78,14 @@ export default function __experimentalUseQuerySelect( mapQuerySelect, deps ) {
78
78
  }, deps );
79
79
  }
80
80
 
81
- type QuerySelector = ( ...args ) => QuerySelectResponse;
82
81
  interface EnrichedSelectors {
83
- [ key: string ]: QuerySelector;
82
+ < Selectors extends Record< string, ( ...args: any[] ) => any > >(
83
+ selectors: Selectors
84
+ ): {
85
+ [ Selector in keyof Selectors ]: (
86
+ ...args: Parameters< Selectors[ Selector ] >
87
+ ) => QuerySelectResponse< ReturnType< Selectors[ Selector ] > >;
88
+ };
84
89
  }
85
90
 
86
91
  /**
@@ -90,14 +95,14 @@ interface EnrichedSelectors {
90
95
  * @param {Object} selectors Selectors to enrich
91
96
  * @return {EnrichedSelectors} Enriched selectors
92
97
  */
93
- const enrichSelectors = memoize( ( selectors ) => {
98
+ const enrichSelectors = memoize( ( ( selectors ) => {
94
99
  const resolvers = {};
95
100
  for ( const selectorName in selectors ) {
96
101
  if ( META_SELECTORS.includes( selectorName ) ) {
97
102
  continue;
98
103
  }
99
104
  Object.defineProperty( resolvers, selectorName, {
100
- get: () => ( ...args ) => {
105
+ get: () => ( ...args: unknown[] ) => {
101
106
  const { getIsResolving, hasFinishedResolution } = selectors;
102
107
  const isResolving = !! getIsResolving( selectorName, args );
103
108
  const hasResolved =
@@ -128,4 +133,4 @@ const enrichSelectors = memoize( ( selectors ) => {
128
133
  } );
129
134
  }
130
135
  return resolvers;
131
- } );
136
+ } ) as EnrichedSelectors );
package/src/index.js CHANGED
@@ -11,41 +11,36 @@ import * as selectors from './selectors';
11
11
  import * as actions from './actions';
12
12
  import * as resolvers from './resolvers';
13
13
  import createLocksActions from './locks/actions';
14
- import { defaultEntities, getMethodName } from './entities';
14
+ import { rootEntitiesConfig, getMethodName } from './entities';
15
15
  import { STORE_NAME } from './name';
16
16
 
17
17
  // The entity selectors/resolvers and actions are shortcuts to their generic equivalents
18
- // (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecordss)
19
- // Instead of getEntityRecord, the consumer could use more user-frieldly named selector: getPostType, getTaxonomy...
18
+ // (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords)
19
+ // Instead of getEntityRecord, the consumer could use more user-friendly named selector: getPostType, getTaxonomy...
20
20
  // The "kind" and the "name" of the entity are combined to generate these shortcuts.
21
21
 
22
- const entitySelectors = defaultEntities.reduce( ( result, entity ) => {
22
+ const entitySelectors = rootEntitiesConfig.reduce( ( result, entity ) => {
23
23
  const { kind, name } = entity;
24
24
  result[ getMethodName( kind, name ) ] = ( state, key, query ) =>
25
25
  selectors.getEntityRecord( state, kind, name, key, query );
26
- result[ getMethodName( kind, name, 'get', true ) ] = ( state, ...args ) =>
27
- selectors.getEntityRecords( state, kind, name, ...args );
26
+ result[ getMethodName( kind, name, 'get', true ) ] = ( state, query ) =>
27
+ selectors.getEntityRecords( state, kind, name, query );
28
28
  return result;
29
29
  }, {} );
30
30
 
31
- const entityResolvers = defaultEntities.reduce( ( result, entity ) => {
31
+ const entityResolvers = rootEntitiesConfig.reduce( ( result, entity ) => {
32
32
  const { kind, name } = entity;
33
33
  result[ getMethodName( kind, name ) ] = ( key, query ) =>
34
34
  resolvers.getEntityRecord( kind, name, key, query );
35
35
  const pluralMethodName = getMethodName( kind, name, 'get', true );
36
36
  result[ pluralMethodName ] = ( ...args ) =>
37
37
  resolvers.getEntityRecords( kind, name, ...args );
38
- result[ pluralMethodName ].shouldInvalidate = ( action, ...args ) =>
39
- resolvers.getEntityRecords.shouldInvalidate(
40
- action,
41
- kind,
42
- name,
43
- ...args
44
- );
38
+ result[ pluralMethodName ].shouldInvalidate = ( action ) =>
39
+ resolvers.getEntityRecords.shouldInvalidate( action, kind, name );
45
40
  return result;
46
41
  }, {} );
47
42
 
48
- const entityActions = defaultEntities.reduce( ( result, entity ) => {
43
+ const entityActions = rootEntitiesConfig.reduce( ( result, entity ) => {
49
44
  const { kind, name } = entity;
50
45
  result[ getMethodName( kind, name, 'save' ) ] = ( key ) =>
51
46
  actions.saveEntityRecord( kind, name, key );
@@ -116,7 +116,7 @@ describe( 'isLockAvailable', () => {
116
116
  store: 'core',
117
117
  path: [
118
118
  'entities',
119
- 'data',
119
+ 'records',
120
120
  'postType',
121
121
  'post',
122
122
  16,
@@ -163,7 +163,7 @@ describe( 'isLockAvailable', () => {
163
163
  entities: {
164
164
  locks: [],
165
165
  children: {
166
- data: {
166
+ records: {
167
167
  locks: [],
168
168
  children: {
169
169
  postType: {
@@ -178,7 +178,7 @@ describe( 'isLockAvailable', () => {
178
178
  path: [
179
179
  'core',
180
180
  'entities',
181
- 'data',
181
+ 'records',
182
182
  'postType',
183
183
  'book',
184
184
  67,
@@ -205,7 +205,7 @@ describe( 'isLockAvailable', () => {
205
205
  isLockAvailable(
206
206
  deepFreeze( subState ),
207
207
  'core',
208
- [ 'entities', 'data', 'postType', 'book', 67 ],
208
+ [ 'entities', 'records', 'postType', 'book', 67 ],
209
209
  { exclusive: false }
210
210
  )
211
211
  ).toBe( false );
@@ -23,10 +23,10 @@ export function receiveItems( items, edits ) {
23
23
  * Returns an action object used in signalling that entity records have been
24
24
  * deleted and they need to be removed from entities state.
25
25
  *
26
- * @param {string} kind Kind of the removed entities.
27
- * @param {string} name Name of the removed entities.
28
- * @param {Array|number} records Record IDs of the removed entities.
29
- * @param {boolean} invalidateCache Controls whether we want to invalidate the cache.
26
+ * @param {string} kind Kind of the removed entities.
27
+ * @param {string} name Name of the removed entities.
28
+ * @param {Array|number|string} records Record IDs of the removed entities.
29
+ * @param {boolean} invalidateCache Controls whether we want to invalidate the cache.
30
30
  * @return {Object} Action object.
31
31
  */
32
32
  export function removeItems( kind, name, records, invalidateCache = false ) {
@@ -70,19 +70,19 @@ export function getQueryParts( query ) {
70
70
  // While in theory, we could exclude "_fields" from the stableKey
71
71
  // because two request with different fields have the same results
72
72
  // We're not able to ensure that because the server can decide to omit
73
- // fields from the response even if we explicitely asked for it.
73
+ // fields from the response even if we explicitly asked for it.
74
74
  // Example: Asking for titles in posts without title support.
75
75
  if ( key === '_fields' ) {
76
- parts.fields = getNormalizedCommaSeparable( value );
76
+ parts.fields = getNormalizedCommaSeparable( value ) ?? [];
77
77
  // Make sure to normalize value for `stableKey`
78
78
  value = parts.fields.join();
79
79
  }
80
80
 
81
81
  // Two requests with different include values cannot have same results.
82
82
  if ( key === 'include' ) {
83
- parts.include = getNormalizedCommaSeparable( value ).map(
84
- Number
85
- );
83
+ parts.include = (
84
+ getNormalizedCommaSeparable( value ) ?? []
85
+ ).map( Number );
86
86
  // Normalize value for `stableKey`.
87
87
  value = parts.include.join();
88
88
  }