PluginProbe
Gutenberg / trunk
Gutenberg vtrunk
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
← All changes | build/scripts/data/index.js +147 -44 23.9.0 → trunk View file →
@@ -1397,9 +1397,9 @@
1397 1397 selector.registry = registry;
1398 1398 }
1399 1399 return selector(state.root, ...args);
1400 1400 };
1401 - boundSelector.__unstableNormalizeArgs = selector.__unstableNormalizeArgs;
1401 + boundSelector.normalizeArgs = getNormalizeArgs(selector);
1402 1402 const resolver = resolvers[selectorName];
1403 1403 if (!resolver) {
1404 1404 boundSelector.hasResolver = false;
1405 1405 return boundSelector;
@@ -1422,8 +1422,15 @@
1422 1422 targetSelector,
1423 1423 selectorArgs
1424 1424 );
1425 1425 }
1426 + const resolver = resolvers[selectorName];
1427 + if (resolver && selectorArgs) {
1428 + selectorArgs = normalizeResolutionArgs(
1429 + resolver,
1430 + selectorArgs
1431 + );
1432 + }
1426 1433 }
1427 1434 const state = store.__unstableOriginalGetState();
1428 1435 return metaDataSelector(
1429 1436 state.metadata,
@@ -1581,13 +1588,20 @@
1581 1588 return async (...args) => selector(...args);
1582 1589 }
1583 1590 return (...args) => new Promise((resolve, reject) => {
1584 1591 const resolver = resolvers[selectorName];
1592 + const resolutionArgs = normalizeResolutionArgs(
1593 + resolver,
1594 + normalize(selector, args)
1595 + );
1585 1596 const hasFinished = () => {
1586 1597 return boundMetadataSelectors.hasFinishedResolution(
1587 1598 selectorName,
1588 1599 args
1589 - ) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled(store.getState(), ...args);
1600 + ) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled(
1601 + store.getState(),
1602 + ...resolutionArgs
1603 + );
1590 1604 };
1591 1605 const finalize = (result2) => {
1592 1606 const hasFailed = boundMetadataSelectors.hasResolutionFailed(
1593 1607 selectorName,
@@ -1664,10 +1678,14 @@
1664 1678 // Add the fulfill method.
1665 1679 };
1666 1680 }
1667 1681 function mapSelectorWithResolver(selector, selectorName, resolver, store, resolversCache, boundMetadataSelectors) {
1668 - function fulfillSelector(args) {
1669 - if (resolversCache.isRunning(selectorName, args) || boundMetadataSelectors.hasStartedResolution(selectorName, args) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled(store.getState(), ...args)) {
1682 + function fulfillSelector(selectorArgs) {
1683 + const args = normalizeResolutionArgs(resolver, selectorArgs);
1684 + if (resolversCache.isRunning(selectorName, args) || boundMetadataSelectors.hasStartedResolution(
1685 + selectorName,
1686 + selectorArgs
1687 + ) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled(store.getState(), ...args)) {
1670 1688 return;
1671 1689 }
1672 1690 resolversCache.markAsRunning(selectorName, args);
1673 1691 setTimeout(async () => {
@@ -1695,16 +1713,27 @@
1695 1713 fulfillSelector(args);
1696 1714 return selector(...args);
1697 1715 };
1698 1716 selectorResolver.hasResolver = true;
1717 + selectorResolver.normalizeArgs = selector.normalizeArgs;
1699 1718 return selectorResolver;
1700 1719 }
1720 + function getNormalizeArgs(selector) {
1721 + return selector.normalizeArgs ?? selector.__unstableNormalizeArgs;
1722 + }
1701 1723 function normalize(selector, args) {
1702 - if (selector.__unstableNormalizeArgs && typeof selector.__unstableNormalizeArgs === "function" && args?.length) {
1703 - return selector.__unstableNormalizeArgs(args);
1724 + const normalizeArgs = getNormalizeArgs(selector);
1725 + if (typeof normalizeArgs === "function" && args?.length) {
1726 + return normalizeArgs(args);
1704 1727 }
1705 1728 return args;
1706 1729 }
1730 + function normalizeResolutionArgs(resolver, args) {
1731 + if (typeof resolver.getResolutionArgs === "function") {
1732 + return resolver.getResolutionArgs(...args);
1733 + }
1734 + return args;
1735 + }
1707 1736
1708 1737 // packages/data/build-module/store/index.mjs
1709 1738 var coreDataStore = {
1710 1739 name: "core/data",
@@ -1757,14 +1786,16 @@
1757 1786 function createEmitter() {
1758 1787 let isPaused = false;
1759 1788 let isPending = false;
1760 1789 const listeners = /* @__PURE__ */ new Set();
1761 - const notifyListeners = () => (
1762 - // We use Array.from to clone the listeners Set
1763 - // This ensures that we don't run a listener
1764 - // that was added as a response to another listener.
1765 - Array.from(listeners).forEach((listener) => listener())
1766 - );
1790 + let clonedListeners = null;
1791 + const notifyListeners = () => {
1792 + clonedListeners ??= Array.from(listeners);
1793 + const currentListeners = clonedListeners;
1794 + for (let i = 0; i < currentListeners.length; i++) {
1795 + currentListeners[i]();
1796 + }
1797 + };
1767 1798 return {
1768 1799 get isPaused() {
1769 1800 return isPaused;
1770 1801 },
@@ -1769,9 +1800,13 @@
1769 1800 return isPaused;
1770 1801 },
1771 1802 subscribe(listener) {
1772 1803 listeners.add(listener);
1773 - return () => listeners.delete(listener);
1804 + clonedListeners = null;
1805 + return () => {
1806 + listeners.delete(listener);
1807 + clonedListeners = null;
1808 + };
1774 1809 },
1775 1810 pause() {
1776 1811 isPaused = true;
1777 1812 },
@@ -1799,11 +1834,41 @@
1799 1834 function createRegistry(storeConfigs = {}, parent = null) {
1800 1835 const stores = {};
1801 1836 const emitter = createEmitter();
1802 1837 let listeningStores = null;
1838 + const pendingListeners = /* @__PURE__ */ new Map();
1803 1839 function globalListener() {
1804 1840 emitter.emit();
1805 1841 }
1842 + function subscribePending(storeName, listener) {
1843 + const pending = { listener };
1844 + let listeners = pendingListeners.get(storeName);
1845 + if (!listeners) {
1846 + listeners = /* @__PURE__ */ new Set();
1847 + pendingListeners.set(storeName, listeners);
1848 + }
1849 + listeners.add(pending);
1850 + return () => {
1851 + pending.unsubscribe?.();
1852 + const stillPending = pendingListeners.get(storeName);
1853 + if (stillPending) {
1854 + stillPending.delete(pending);
1855 + if (stillPending.size === 0) {
1856 + pendingListeners.delete(storeName);
1857 + }
1858 + }
1859 + };
1860 + }
1861 + function connectPendingListeners(name, store) {
1862 + const listeners = pendingListeners.get(name);
1863 + if (!listeners) {
1864 + return;
1865 + }
1866 + pendingListeners.delete(name);
1867 + for (const pending of listeners) {
1868 + pending.unsubscribe = store.subscribe(pending.listener);
1869 + }
1870 + }
1806 1871 const subscribe2 = (listener, storeNameOrDescriptor) => {
1807 1872 if (!storeNameOrDescriptor) {
1808 1873 return emitter.subscribe(listener);
1809 1874 }
@@ -1812,9 +1877,9 @@
1812 1877 if (store) {
1813 1878 return store.subscribe(listener);
1814 1879 }
1815 1880 if (!parent) {
1816 - return emitter.subscribe(listener);
1881 + return subscribePending(storeName, listener);
1817 1882 }
1818 1883 return parent.subscribe(listener, storeNameOrDescriptor);
1819 1884 };
1820 1885 function select3(storeNameOrDescriptor) {
@@ -1891,25 +1956,13 @@
1891 1956 if (typeof store.subscribe !== "function") {
1892 1957 throw new TypeError("store.subscribe must be a function");
1893 1958 }
1894 1959 store.emitter = createEmitter();
1895 - const currentSubscribe = store.subscribe;
1896 - store.subscribe = (listener) => {
1897 - const unsubscribeFromEmitter = store.emitter.subscribe(listener);
1898 - const unsubscribeFromStore = currentSubscribe(() => {
1899 - if (store.emitter.isPaused) {
1900 - store.emitter.emit();
1901 - return;
1902 - }
1903 - listener();
1904 - });
1905 - return () => {
1906 - unsubscribeFromStore?.();
1907 - unsubscribeFromEmitter?.();
1908 - };
1909 - };
1960 + store.subscribe(() => store.emitter.emit());
1961 + store.subscribe = (listener) => store.emitter.subscribe(listener);
1910 1962 stores[name] = store;
1911 1963 store.subscribe(globalListener);
1964 + connectPendingListeners(name, store);
1912 1965 if (parent) {
1913 1966 try {
1914 1967 unlock(store.store).registerPrivateActions(
1915 1968 unlock(parent).privateActionsOf(name)
@@ -2220,10 +2273,9 @@
2220 2273 // packages/data/build-module/components/async-mode-provider/context.mjs
2221 2274 var import_element3 = __toESM(require_element(), 1);
2222 2275 var Context2 = (0, import_element3.createContext)(false);
2223 2276 Context2.displayName = "AsyncModeContext";
2224 - var { Consumer: Consumer2, Provider: Provider2 } = Context2;
2225 - var context_default2 = Provider2;
2277 + var context_default2 = Context2.Provider;
2226 2278
2227 2279 // packages/data/build-module/components/async-mode-provider/use-async-mode.mjs
2228 2280 function useAsyncMode() {
2229 2281 return (0, import_element4.useContext)(Context2);
@@ -2240,8 +2292,41 @@
2240 2292 "The `useSelect` hook returns different values when called with the same state and parameters.\nThis can lead to unnecessary re-renders and performance issues if not fixed.\n\nNon-equal value keys: %s\n\n",
2241 2293 keys.join(", ")
2242 2294 );
2243 2295 }
2296 + var deferredBuckets = /* @__PURE__ */ new WeakMap();
2297 + function subscribeDeferred(registry, storeName, listener) {
2298 + let buckets = deferredBuckets.get(registry);
2299 + if (!buckets) {
2300 + buckets = /* @__PURE__ */ new Map();
2301 + deferredBuckets.set(registry, buckets);
2302 + }
2303 + let addToBucket = buckets.get(storeName);
2304 + if (!addToBucket) {
2305 + const listeners = /* @__PURE__ */ new Set();
2306 + const flush = () => {
2307 + for (const { context, callback } of listeners) {
2308 + renderQueue.add(context, callback);
2309 + }
2310 + };
2311 + const unsubscribe = registry.subscribe(
2312 + () => renderQueue.add(listeners, flush),
2313 + storeName
2314 + );
2315 + addToBucket = (newListener) => {
2316 + listeners.add(newListener);
2317 + return () => {
2318 + if (listeners.delete(newListener) && listeners.size === 0) {
2319 + buckets.delete(storeName);
2320 + renderQueue.cancel(listeners);
2321 + unsubscribe();
2322 + }
2323 + };
2324 + };
2325 + buckets.set(storeName, addToBucket);
2326 + }
2327 + return addToBucket(listener);
2328 + }
2244 2329 function Store(registry, suspense) {
2245 2330 const select3 = suspense ? registry.suspendSelect : registry.select;
2246 2331 const queueContext = {};
2247 2332 let lastMapSelect;
@@ -2269,25 +2354,34 @@
2269 2354 const onStoreChange = () => {
2270 2355 lastMapResultValid = false;
2271 2356 listener();
2272 2357 };
2273 - const onChange = () => {
2358 + function listenToStore(storeName) {
2274 2359 if (lastIsAsync) {
2275 - renderQueue.add(queueContext, onStoreChange);
2276 - } else {
2277 - onStoreChange();
2360 + return subscribeDeferred(registry, storeName, {
2361 + context: queueContext,
2362 + callback: onStoreChange
2363 + });
2278 2364 }
2279 - };
2280 - const unsubs = [];
2365 + return registry.subscribe(onStoreChange, storeName);
2366 + }
2367 + const unsubs = /* @__PURE__ */ new Map();
2281 2368 function subscribeStore(storeName) {
2282 - unsubs.push(registry.subscribe(onChange, storeName));
2369 + unsubs.set(storeName, listenToStore(storeName));
2283 2370 }
2371 + function resubscribeStores() {
2372 + for (const [storeName, unsub] of unsubs) {
2373 + unsub?.();
2374 + unsubs.set(storeName, listenToStore(storeName));
2375 + }
2376 + }
2284 2377 for (const storeName of activeStores) {
2285 2378 subscribeStore(storeName);
2286 2379 }
2287 - activeSubscriptions.add(subscribeStore);
2380 + const subscription = { subscribeStore, resubscribeStores };
2381 + activeSubscriptions.add(subscription);
2288 2382 return () => {
2289 - activeSubscriptions.delete(subscribeStore);
2383 + activeSubscriptions.delete(subscription);
2290 2384 for (const unsub of unsubs.values()) {
2291 2385 unsub?.();
2292 2386 }
2293 2387 renderQueue.cancel(queueContext);
@@ -2299,13 +2393,18 @@
2299 2393 continue;
2300 2394 }
2301 2395 activeStores.push(newStore);
2302 2396 for (const subscription of activeSubscriptions) {
2303 - subscription(newStore);
2397 + subscription.subscribeStore(newStore);
2304 2398 }
2305 2399 }
2306 2400 }
2307 - return { subscribe: subscribe2, updateStores };
2401 + function switchMode() {
2402 + for (const subscription of activeSubscriptions) {
2403 + subscription.resubscribeStores();
2404 + }
2405 + }
2406 + return { subscribe: subscribe2, updateStores, switchMode };
2308 2407 };
2309 2408 return (mapSelect, isAsync) => {
2310 2409 function updateValue() {
2311 2410 if (lastMapResultValid && mapSelect === lastMapSelect) {
@@ -2342,14 +2441,18 @@
2342 2441 function getValue() {
2343 2442 updateValue();
2344 2443 return lastMapResult;
2345 2444 }
2346 - if (lastIsAsync && !isAsync) {
2445 + const wasAsync = lastIsAsync;
2446 + lastIsAsync = isAsync;
2447 + if (wasAsync && !isAsync) {
2347 2448 lastMapResultValid = false;
2348 2449 renderQueue.cancel(queueContext);
2349 2450 }
2350 2451 updateValue();
2351 - lastIsAsync = isAsync;
2452 + if (wasAsync !== isAsync) {
2453 + subscriber.switchMode();
2454 + }
2352 2455 return { subscribe: subscriber.subscribe, getValue };
2353 2456 };
2354 2457 }
2355 2458 function _useStaticSelect(storeName) {