@wordpress/core-data 7.44.0 → 7.45.0

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 (42) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/entities.cjs +0 -4
  3. package/build/entities.cjs.map +2 -2
  4. package/build/queried-data/reducer.cjs +3 -3
  5. package/build/queried-data/reducer.cjs.map +2 -2
  6. package/build/queried-data/selectors.cjs +13 -16
  7. package/build/queried-data/selectors.cjs.map +2 -2
  8. package/build/utils/crdt.cjs +8 -2
  9. package/build/utils/crdt.cjs.map +2 -2
  10. package/build/utils/index.cjs +0 -3
  11. package/build/utils/index.cjs.map +2 -2
  12. package/build-module/entities.mjs +0 -4
  13. package/build-module/entities.mjs.map +2 -2
  14. package/build-module/queried-data/reducer.mjs +5 -10
  15. package/build-module/queried-data/reducer.mjs.map +2 -2
  16. package/build-module/queried-data/selectors.mjs +13 -16
  17. package/build-module/queried-data/selectors.mjs.map +2 -2
  18. package/build-module/utils/crdt.mjs +8 -2
  19. package/build-module/utils/crdt.mjs.map +2 -2
  20. package/build-module/utils/index.mjs +12 -14
  21. package/build-module/utils/index.mjs.map +2 -2
  22. package/build-types/entities.d.ts.map +1 -1
  23. package/build-types/queried-data/reducer.d.ts.map +1 -1
  24. package/build-types/queried-data/selectors.d.ts +5 -7
  25. package/build-types/queried-data/selectors.d.ts.map +1 -1
  26. package/build-types/utils/crdt.d.ts.map +1 -1
  27. package/build-types/utils/index.d.ts +0 -1
  28. package/package.json +18 -18
  29. package/src/entities.js +0 -4
  30. package/src/queried-data/reducer.js +6 -11
  31. package/src/queried-data/selectors.js +16 -25
  32. package/src/utils/crdt.ts +15 -3
  33. package/src/utils/index.js +0 -1
  34. package/src/utils/test/crdt.ts +24 -0
  35. package/build/utils/on-sub-key.cjs +0 -46
  36. package/build/utils/on-sub-key.cjs.map +0 -7
  37. package/build-module/utils/on-sub-key.mjs +0 -21
  38. package/build-module/utils/on-sub-key.mjs.map +0 -7
  39. package/build-types/utils/on-sub-key.d.ts +0 -4
  40. package/build-types/utils/on-sub-key.d.ts.map +0 -1
  41. package/src/utils/on-sub-key.js +0 -35
  42. package/src/utils/test/on-sub-key.js +0 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/core-data",
3
- "version": "7.44.0",
3
+ "version": "7.45.0",
4
4
  "description": "Access to and manipulation of core WordPress entities.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -49,22 +49,22 @@
49
49
  "build-module/index.mjs"
50
50
  ],
51
51
  "dependencies": {
52
- "@wordpress/api-fetch": "^7.44.0",
53
- "@wordpress/block-editor": "^15.17.0",
54
- "@wordpress/blocks": "^15.17.0",
55
- "@wordpress/compose": "^7.44.0",
56
- "@wordpress/data": "^10.44.0",
57
- "@wordpress/deprecated": "^4.44.0",
58
- "@wordpress/element": "^6.44.0",
59
- "@wordpress/html-entities": "^4.44.0",
60
- "@wordpress/i18n": "^6.17.0",
61
- "@wordpress/is-shallow-equal": "^5.44.0",
62
- "@wordpress/private-apis": "^1.44.0",
63
- "@wordpress/rich-text": "^7.44.0",
64
- "@wordpress/sync": "^1.44.0",
65
- "@wordpress/undo-manager": "^1.44.0",
66
- "@wordpress/url": "^4.44.0",
67
- "@wordpress/warning": "^3.44.0",
52
+ "@wordpress/api-fetch": "^7.45.0",
53
+ "@wordpress/block-editor": "^15.18.0",
54
+ "@wordpress/blocks": "^15.18.0",
55
+ "@wordpress/compose": "^7.45.0",
56
+ "@wordpress/data": "^10.45.0",
57
+ "@wordpress/deprecated": "^4.45.0",
58
+ "@wordpress/element": "^6.45.0",
59
+ "@wordpress/html-entities": "^4.45.0",
60
+ "@wordpress/i18n": "^6.18.0",
61
+ "@wordpress/is-shallow-equal": "^5.45.0",
62
+ "@wordpress/private-apis": "^1.45.0",
63
+ "@wordpress/rich-text": "^7.45.0",
64
+ "@wordpress/sync": "^1.45.0",
65
+ "@wordpress/undo-manager": "^1.45.0",
66
+ "@wordpress/url": "^4.45.0",
67
+ "@wordpress/warning": "^3.45.0",
68
68
  "change-case": "^4.1.2",
69
69
  "equivalent-key-map": "^0.2.2",
70
70
  "fast-deep-equal": "^3.1.3",
@@ -84,5 +84,5 @@
84
84
  "publishConfig": {
85
85
  "access": "public"
86
86
  },
87
- "gitHead": "b862d8c84121a47bbeff882f6c87e61681ce2e0d"
87
+ "gitHead": "8c229eaed0e88c9827e2da3d73a78f9ddd77714b"
88
88
  }
package/src/entities.js CHANGED
@@ -51,10 +51,6 @@ export const rootEntitiesConfig = [
51
51
  'home',
52
52
  'image_sizes',
53
53
  'image_size_threshold',
54
- 'image_output_formats',
55
- 'jpeg_interlaced',
56
- 'png_interlaced',
57
- 'gif_interlaced',
58
54
  'name',
59
55
  'site_icon',
60
56
  'site_icon_url',
@@ -1,18 +1,13 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { combineReducers } from '@wordpress/data';
4
+ import { combineReducers, keyedReducer } from '@wordpress/data';
5
5
  import { compose } from '@wordpress/compose';
6
6
 
7
7
  /**
8
8
  * Internal dependencies
9
9
  */
10
- import {
11
- conservativeMapItem,
12
- ifMatchingAction,
13
- replaceAction,
14
- onSubKey,
15
- } from '../utils';
10
+ import { conservativeMapItem, ifMatchingAction, replaceAction } from '../utils';
16
11
  import { DEFAULT_ENTITY_KEY } from '../entities';
17
12
  import getQueryParts from './get-query-parts';
18
13
 
@@ -221,11 +216,11 @@ const receiveQueries = compose( [
221
216
  // an unhandled action.
222
217
  ifMatchingAction( ( action ) => 'query' in action ),
223
218
 
224
- // Inject query parts into action for use both in `onSubKey` and reducer.
219
+ // Inject query parts into action for use both in `keyedReducer` and reducer.
225
220
  replaceAction( ( action ) => {
226
221
  // `ifMatchingAction` still passes on initialization, where state is
227
222
  // undefined and a query is not assigned. Avoid attempting to parse
228
- // parts. `onSubKey` will omit by lack of `stableKey`.
223
+ // parts. `keyedReducer` will omit by lack of `stableKey`.
229
224
  if ( action.query ) {
230
225
  return {
231
226
  ...action,
@@ -236,11 +231,11 @@ const receiveQueries = compose( [
236
231
  return action;
237
232
  } ),
238
233
 
239
- onSubKey( 'context' ),
234
+ keyedReducer( 'context' ),
240
235
 
241
236
  // Queries shape is shared, but keyed by query `stableKey` part. Original
242
237
  // reducer tracks only a single query object.
243
- onSubKey( 'stableKey' ),
238
+ keyedReducer( 'stableKey' ),
244
239
  ] )( ( state = {}, action ) => {
245
240
  if ( action.type !== 'RECEIVE_ITEMS' ) {
246
241
  return state;
@@ -3,11 +3,6 @@
3
3
  */
4
4
  import EquivalentKeyMap from 'equivalent-key-map';
5
5
 
6
- /**
7
- * WordPress dependencies
8
- */
9
- import { createSelector } from '@wordpress/data';
10
-
11
6
  /**
12
7
  * Internal dependencies
13
8
  */
@@ -114,11 +109,9 @@ function getQueriedItemsUncached( state, query, options = {} ) {
114
109
 
115
110
  /**
116
111
  * Returns items for a given query, or null if the items are not known. Caches
117
- * result both per state (by reference) and per query (by deep equality).
118
- * The caching approach is intended to be durable to query objects which are
119
- * deeply but not referentially equal, since otherwise:
112
+ * result per state (by reference) and per query (by deep equality), so that:
120
113
  *
121
- * `getQueriedItems( state, {} ) !== getQueriedItems( state, {} )`
114
+ * `getQueriedItems( state, {} ) === getQueriedItems( state, {} )`
122
115
  *
123
116
  * @param {Object} state State object.
124
117
  * @param {?Object} query Optional query.
@@ -127,24 +120,22 @@ function getQueriedItemsUncached( state, query, options = {} ) {
127
120
  *
128
121
  * @return {?Array} Query items.
129
122
  */
130
- export const getQueriedItems = createSelector(
131
- ( state, query = {}, options = {} ) => {
132
- let queriedItemsCache = queriedItemsCacheByState.get( state );
133
- if ( queriedItemsCache ) {
134
- const queriedItems = queriedItemsCache.get( query );
135
- if ( queriedItems !== undefined ) {
136
- return queriedItems;
137
- }
138
- } else {
139
- queriedItemsCache = new EquivalentKeyMap();
140
- queriedItemsCacheByState.set( state, queriedItemsCache );
123
+ export function getQueriedItems( state, query = {}, options = {} ) {
124
+ let queriedItemsCache = queriedItemsCacheByState.get( state );
125
+ if ( queriedItemsCache ) {
126
+ const queriedItems = queriedItemsCache.get( query );
127
+ if ( queriedItems !== undefined ) {
128
+ return queriedItems;
141
129
  }
142
-
143
- const items = getQueriedItemsUncached( state, query, options );
144
- queriedItemsCache.set( query, items );
145
- return items;
130
+ } else {
131
+ queriedItemsCache = new EquivalentKeyMap();
132
+ queriedItemsCacheByState.set( state, queriedItemsCache );
146
133
  }
147
- );
134
+
135
+ const items = getQueriedItemsUncached( state, query, options );
136
+ queriedItemsCache.set( query, items );
137
+ return items;
138
+ }
148
139
 
149
140
  export function getQueriedTotalItems( state, query = {} ) {
150
141
  const { stableKey, context } = getQueryParts( query );
package/src/utils/crdt.ts CHANGED
@@ -340,17 +340,29 @@ export function getPostChangesFromCRDTDoc(
340
340
  }
341
341
 
342
342
  case 'meta': {
343
+ const currentMeta =
344
+ ( currentValue as PostChanges[ 'meta' ] ) ?? {};
345
+
343
346
  allowedMetaChanges = Object.fromEntries(
344
347
  Object.entries( newValue ?? {} ).filter(
345
- ( [ metaKey ] ) =>
346
- ! disallowedPostMetaKeys.has( metaKey )
348
+ ( [ metaKey ] ) => {
349
+ if ( disallowedPostMetaKeys.has( metaKey ) ) {
350
+ return false;
351
+ }
352
+
353
+ // Ignore meta keys that are no longer registered
354
+ // for this post (absent from the REST response).
355
+ // Without this, orphaned CRDT meta would mark
356
+ // the post permanently dirty.
357
+ return metaKey in currentMeta;
358
+ }
347
359
  )
348
360
  );
349
361
 
350
362
  // Merge the allowed meta changes with the current meta values since
351
363
  // not all meta properties are synced.
352
364
  const mergedValue = {
353
- ...( currentValue as PostChanges[ 'meta' ] ),
365
+ ...currentMeta,
354
366
  ...allowedMetaChanges,
355
367
  };
356
368
 
@@ -2,7 +2,6 @@ export { default as conservativeMapItem } from './conservative-map-item';
2
2
  export { default as getNormalizedCommaSeparable } from './get-normalized-comma-separable';
3
3
  export { default as ifMatchingAction } from './if-matching-action';
4
4
  export { default as forwardResolver } from './forward-resolver';
5
- export { default as onSubKey } from './on-sub-key';
6
5
  export { default as replaceAction } from './replace-action';
7
6
  export { default as withWeakMapCache } from './with-weak-map-cache';
8
7
  export { default as setNestedValue } from './set-nested-value';
@@ -773,6 +773,30 @@ describe( 'crdt', () => {
773
773
  } );
774
774
  } );
775
775
 
776
+ it( 'excludes orphaned meta keys not present on the edited record', () => {
777
+ // If post meta is registered, saved (landing in a CRDT doc),
778
+ // then unregistered, it can permanently mark the record dirty.
779
+ // Orphaned values should not show up as a change.
780
+ const metaMap = createYMap();
781
+ metaMap.set( 'registered_meta', 'value' );
782
+ metaMap.set( 'orphaned_meta', 'stale value' );
783
+ map.set( 'meta', metaMap );
784
+
785
+ const editedRecord = {
786
+ meta: {
787
+ registered_meta: 'value',
788
+ },
789
+ } as unknown as Post;
790
+
791
+ const changes = getPostChangesFromCRDTDoc(
792
+ doc,
793
+ editedRecord,
794
+ defaultSyncedProperties
795
+ );
796
+
797
+ expect( changes ).not.toHaveProperty( 'meta' );
798
+ } );
799
+
776
800
  it( 'excludes disallowed meta keys in changes', () => {
777
801
  const metaMap = createYMap();
778
802
  metaMap.set( 'public_meta', 'new value' );
@@ -1,46 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // packages/core-data/src/utils/on-sub-key.js
21
- var on_sub_key_exports = {};
22
- __export(on_sub_key_exports, {
23
- default: () => on_sub_key_default,
24
- onSubKey: () => onSubKey
25
- });
26
- module.exports = __toCommonJS(on_sub_key_exports);
27
- var onSubKey = (actionProperty) => (reducer) => (state = {}, action) => {
28
- const key = action[actionProperty];
29
- if (key === void 0) {
30
- return state;
31
- }
32
- const nextKeyState = reducer(state[key], action);
33
- if (nextKeyState === state[key]) {
34
- return state;
35
- }
36
- return {
37
- ...state,
38
- [key]: nextKeyState
39
- };
40
- };
41
- var on_sub_key_default = onSubKey;
42
- // Annotate the CommonJS export names for ESM import in node:
43
- 0 && (module.exports = {
44
- onSubKey
45
- });
46
- //# sourceMappingURL=on-sub-key.cjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/utils/on-sub-key.js"],
4
- "sourcesContent": ["/** @typedef {import('../types').AnyFunction} AnyFunction */\n\n/**\n * Higher-order reducer creator which creates a combined reducer object, keyed\n * by a property on the action object.\n *\n * @param {string} actionProperty Action property by which to key object.\n *\n * @return {AnyFunction} Higher-order reducer.\n */\nexport const onSubKey =\n\t( actionProperty ) =>\n\t( reducer ) =>\n\t( state = {}, action ) => {\n\t\t// Retrieve subkey from action. Do not track if undefined; useful for cases\n\t\t// where reducer is scoped by action shape.\n\t\tconst key = action[ actionProperty ];\n\t\tif ( key === undefined ) {\n\t\t\treturn state;\n\t\t}\n\n\t\t// Avoid updating state if unchanged. Note that this also accounts for a\n\t\t// reducer which returns undefined on a key which is not yet tracked.\n\t\tconst nextKeyState = reducer( state[ key ], action );\n\t\tif ( nextKeyState === state[ key ] ) {\n\t\t\treturn state;\n\t\t}\n\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ key ]: nextKeyState,\n\t\t};\n\t};\n\nexport default onSubKey;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUO,IAAM,WACZ,CAAE,mBACF,CAAE,YACF,CAAE,QAAQ,CAAC,GAAG,WAAY;AAGzB,QAAM,MAAM,OAAQ,cAAe;AACnC,MAAK,QAAQ,QAAY;AACxB,WAAO;AAAA,EACR;AAIA,QAAM,eAAe,QAAS,MAAO,GAAI,GAAG,MAAO;AACnD,MAAK,iBAAiB,MAAO,GAAI,GAAI;AACpC,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,GAAG;AAAA,IACH,CAAE,GAAI,GAAG;AAAA,EACV;AACD;AAED,IAAO,qBAAQ;",
6
- "names": []
7
- }
@@ -1,21 +0,0 @@
1
- // packages/core-data/src/utils/on-sub-key.js
2
- var onSubKey = (actionProperty) => (reducer) => (state = {}, action) => {
3
- const key = action[actionProperty];
4
- if (key === void 0) {
5
- return state;
6
- }
7
- const nextKeyState = reducer(state[key], action);
8
- if (nextKeyState === state[key]) {
9
- return state;
10
- }
11
- return {
12
- ...state,
13
- [key]: nextKeyState
14
- };
15
- };
16
- var on_sub_key_default = onSubKey;
17
- export {
18
- on_sub_key_default as default,
19
- onSubKey
20
- };
21
- //# sourceMappingURL=on-sub-key.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/utils/on-sub-key.js"],
4
- "sourcesContent": ["/** @typedef {import('../types').AnyFunction} AnyFunction */\n\n/**\n * Higher-order reducer creator which creates a combined reducer object, keyed\n * by a property on the action object.\n *\n * @param {string} actionProperty Action property by which to key object.\n *\n * @return {AnyFunction} Higher-order reducer.\n */\nexport const onSubKey =\n\t( actionProperty ) =>\n\t( reducer ) =>\n\t( state = {}, action ) => {\n\t\t// Retrieve subkey from action. Do not track if undefined; useful for cases\n\t\t// where reducer is scoped by action shape.\n\t\tconst key = action[ actionProperty ];\n\t\tif ( key === undefined ) {\n\t\t\treturn state;\n\t\t}\n\n\t\t// Avoid updating state if unchanged. Note that this also accounts for a\n\t\t// reducer which returns undefined on a key which is not yet tracked.\n\t\tconst nextKeyState = reducer( state[ key ], action );\n\t\tif ( nextKeyState === state[ key ] ) {\n\t\t\treturn state;\n\t\t}\n\n\t\treturn {\n\t\t\t...state,\n\t\t\t[ key ]: nextKeyState,\n\t\t};\n\t};\n\nexport default onSubKey;\n"],
5
- "mappings": ";AAUO,IAAM,WACZ,CAAE,mBACF,CAAE,YACF,CAAE,QAAQ,CAAC,GAAG,WAAY;AAGzB,QAAM,MAAM,OAAQ,cAAe;AACnC,MAAK,QAAQ,QAAY;AACxB,WAAO;AAAA,EACR;AAIA,QAAM,eAAe,QAAS,MAAO,GAAI,GAAG,MAAO;AACnD,MAAK,iBAAiB,MAAO,GAAI,GAAI;AACpC,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,GAAG;AAAA,IACH,CAAE,GAAI,GAAG;AAAA,EACV;AACD;AAED,IAAO,qBAAQ;",
6
- "names": []
7
- }
@@ -1,4 +0,0 @@
1
- export function onSubKey(actionProperty: string): AnyFunction;
2
- export default onSubKey;
3
- export type AnyFunction = import("../types").AnyFunction;
4
- //# sourceMappingURL=on-sub-key.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"on-sub-key.d.ts","sourceRoot":"","sources":["../../src/utils/on-sub-key.js"],"names":[],"mappings":"AAUO,yCAJI,MAAM,GAEL,WAAW,CAwBrB;;0BAhCY,OAAO,UAAU,EAAE,WAAW"}
@@ -1,35 +0,0 @@
1
- /** @typedef {import('../types').AnyFunction} AnyFunction */
2
-
3
- /**
4
- * Higher-order reducer creator which creates a combined reducer object, keyed
5
- * by a property on the action object.
6
- *
7
- * @param {string} actionProperty Action property by which to key object.
8
- *
9
- * @return {AnyFunction} Higher-order reducer.
10
- */
11
- export const onSubKey =
12
- ( actionProperty ) =>
13
- ( reducer ) =>
14
- ( state = {}, action ) => {
15
- // Retrieve subkey from action. Do not track if undefined; useful for cases
16
- // where reducer is scoped by action shape.
17
- const key = action[ actionProperty ];
18
- if ( key === undefined ) {
19
- return state;
20
- }
21
-
22
- // Avoid updating state if unchanged. Note that this also accounts for a
23
- // reducer which returns undefined on a key which is not yet tracked.
24
- const nextKeyState = reducer( state[ key ], action );
25
- if ( nextKeyState === state[ key ] ) {
26
- return state;
27
- }
28
-
29
- return {
30
- ...state,
31
- [ key ]: nextKeyState,
32
- };
33
- };
34
-
35
- export default onSubKey;
@@ -1,46 +0,0 @@
1
- /**
2
- * External dependencies
3
- */
4
- import deepFreeze from 'deep-freeze';
5
-
6
- /**
7
- * Internal dependencies
8
- */
9
- import onSubKey from '../on-sub-key';
10
-
11
- describe( 'onSubKey', () => {
12
- function createEnhancedReducer( actionProperty ) {
13
- const enhanceReducer = onSubKey( actionProperty );
14
- return enhanceReducer(
15
- ( state, action ) => 'Called by ' + action.caller
16
- );
17
- }
18
-
19
- it( 'should default to an empty object', () => {
20
- const reducer = createEnhancedReducer( 'caller' );
21
- const nextState = reducer( undefined, { type: '@@INIT' } );
22
-
23
- expect( nextState ).toEqual( {} );
24
- } );
25
-
26
- it( 'should ignore actions where property not present', () => {
27
- const state = deepFreeze( {} );
28
- const reducer = createEnhancedReducer( 'caller' );
29
- const nextState = reducer( state, { type: 'DO_FOO' } );
30
-
31
- expect( nextState ).toBe( state );
32
- } );
33
-
34
- it( 'should key by action property', () => {
35
- const reducer = createEnhancedReducer( 'caller' );
36
-
37
- let state = deepFreeze( {} );
38
- state = reducer( state, { type: 'DO_FOO', caller: 1 } );
39
- state = reducer( state, { type: 'DO_FOO', caller: 2 } );
40
-
41
- expect( state ).toEqual( {
42
- 1: 'Called by 1',
43
- 2: 'Called by 2',
44
- } );
45
- } );
46
- } );