From c785053b868bf32233276ae8a8979e0c7e915e42 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Thu, 27 Jun 2024 06:01:13 -0300 Subject: [PATCH] Deprecate proxyLazy and proxyInner top level destructure --- src/components/PluginSettings/index.tsx | 6 ++-- src/plugins/spotifyControls/SpotifyStore.ts | 4 +-- src/utils/lazy.ts | 25 ++++------------ src/utils/proxyInner.ts | 33 +++------------------ src/webpack/api.tsx | 6 ++-- 5 files changed, 17 insertions(+), 57 deletions(-) diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx index e7ad6051d..8d1365b88 100644 --- a/src/components/PluginSettings/index.tsx +++ b/src/components/PluginSettings/index.tsx @@ -40,7 +40,7 @@ import { Alerts, Button, Card, Forms, lodash, Parser, React, Select, Text, TextI import Plugins, { ExcludedPlugins } from "~plugins"; // Avoid circular dependency -const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() => require("../../plugins")) as typeof import("../../plugins"); +const PluginManager = proxyLazy(() => require("../../plugins")) as typeof import("../../plugins"); const cl = classNameFactory("vc-plugins-"); const logger = new Logger("PluginSettings", "#a6d189"); @@ -109,7 +109,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on // If we're enabling a plugin, make sure all deps are enabled recursively. if (!wasEnabled) { - const { restartNeeded, failures } = startDependenciesRecursive(plugin); + const { restartNeeded, failures } = PluginManager.startDependenciesRecursive(plugin); if (failures.length) { logger.error(`Failed to start dependencies for ${plugin.name}: ${failures.join(", ")}`); showNotice("Failed to start dependencies: " + failures.join(", "), "Close", () => null); @@ -135,7 +135,7 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on return; } - const result = wasEnabled ? stopPlugin(plugin) : startPlugin(plugin); + const result = wasEnabled ? PluginManager.stopPlugin(plugin) : PluginManager.startPlugin(plugin); if (!result) { settings.enabled = false; diff --git a/src/plugins/spotifyControls/SpotifyStore.ts b/src/plugins/spotifyControls/SpotifyStore.ts index fe5fc085b..a148d73f3 100644 --- a/src/plugins/spotifyControls/SpotifyStore.ts +++ b/src/plugins/spotifyControls/SpotifyStore.ts @@ -21,7 +21,7 @@ import { findByProps, webpackDependantLazy } from "@webpack"; import { Flux, FluxDispatcher } from "@webpack/common"; // Avoid circular dependency -const { settings } = proxyLazy(() => require(".")) as typeof import("."); +const SpotifyControls = proxyLazy(() => require(".")) as typeof import("."); export interface Track { id: string; @@ -91,7 +91,7 @@ export const SpotifyStore = webpackDependantLazy(() => { public isSettingPosition = false; public openExternal(path: string) { - const url = settings.store.useSpotifyUris || Vencord.Plugins.isPluginEnabled("OpenInApp") + const url = SpotifyControls.settings.store.useSpotifyUris || Vencord.Plugins.isPluginEnabled("OpenInApp") ? "spotify:" + path.replaceAll("/", (_, idx) => idx === 0 ? "" : ":") : "https://open.spotify.com" + path; diff --git a/src/utils/lazy.ts b/src/utils/lazy.ts index d1bb3e0ae..4001c7700 100644 --- a/src/utils/lazy.ts +++ b/src/utils/lazy.ts @@ -73,16 +73,16 @@ const handler: ProxyHandler = { * Wraps the result of factory in a Proxy you can consume as if it wasn't lazy. * On first property access, the factory is evaluated. * + * IMPORTANT: + * Destructuring at top level is not supported for proxyLazy. + * * @param factory Factory returning the result * @param attempts How many times to try to evaluate the factory before giving up * @returns Result of factory function */ -export function proxyLazy(factory: () => T, attempts = 5, isChild = false): ProxyLazy { +export function proxyLazy(factory: () => T, attempts = 5): ProxyLazy { const get = makeLazy(factory, attempts, { isIndirect: true }); - let isSameTick = true; - if (!isChild) setTimeout(() => isSameTick = false, 0); - const proxyDummy = Object.assign(function () { }, { [SYM_LAZY_GET]() { if (!proxyDummy[SYM_LAZY_CACHED]) { @@ -111,27 +111,12 @@ export function proxyLazy(factory: () => T, attempts = 5, isChild return Reflect.get(target, p, receiver); } - // If we're still in the same tick, it means the lazy was immediately used. - // thus, we lazy proxy the get access to make things like destructuring work as expected - // meow here will also be a lazy - // `const { meow } = proxyLazy(() => ({ meow: [] }));` - if (!isChild && isSameTick) { - return proxyLazy( - () => { - const lazyTarget = target[SYM_LAZY_GET](); - return Reflect.get(lazyTarget, p, lazyTarget); - }, - attempts, - true - ); - } - const lazyTarget = target[SYM_LAZY_GET](); if (typeof lazyTarget === "object" || typeof lazyTarget === "function") { return Reflect.get(lazyTarget, p, lazyTarget); } - throw new Error("proxyLazy called on a primitive value. This can happen if you try to destructure a primitive at the same tick as the proxy was created."); + throw new Error("proxyLazy called on a primitive value."); } }); diff --git a/src/utils/proxyInner.ts b/src/utils/proxyInner.ts index 0c02febeb..5b4659c3d 100644 --- a/src/utils/proxyInner.ts +++ b/src/utils/proxyInner.ts @@ -48,18 +48,17 @@ const handler: ProxyHandler = { * A proxy which has an inner value that can be set later. * When a property is accessed, the proxy looks for the property value in its inner value, and errors if it's not set. * + * IMPORTANT: + * Destructuring at top level is not supported for proxyInner. + * * @param err The error message to throw when the inner value is not set * @param primitiveErr The error message to throw when the inner value is a primitive * @returns A proxy which will act like the inner value when accessed */ export function proxyInner( errMsg = "Proxy inner value is undefined, setInnerValue was never called.", - primitiveErrMsg = "proxyInner called on a primitive value. This can happen if you try to destructure a primitive at the same tick as the proxy was created.", - isChild = false + primitiveErrMsg = "proxyInner called on a primitive value." ): [proxy: ProxyInner, setInnerValue: (innerValue: T) => void] { - let isSameTick = true; - if (!isChild) setTimeout(() => isSameTick = false, 0); - const proxyDummy = Object.assign(function () { }, { [SYM_PROXY_INNER_GET]: function () { if (proxyDummy[SYM_PROXY_INNER_VALUE] == null) { @@ -78,24 +77,6 @@ export function proxyInner( return Reflect.get(target, p, receiver); } - // If we're still in the same tick, it means the proxy was immediately used. - // And, if the inner value is still nullish, it means the proxy was used before setInnerValue was called. - // So, proxy the get access to make things like destructuring work as expected. - // We dont need to proxy if the inner value is available, and recursiveSetInnerValue won't ever be called anyways, - // because the top setInnerValue was called before we proxied the get access - // example here will also be a proxy: - // `const { example } = findByProps("example");` - if (isSameTick && !isChild && proxyDummy[SYM_PROXY_INNER_VALUE] == null) { - const [recursiveProxy, recursiveSetInnerValue] = proxyInner(errMsg, primitiveErrMsg, true); - - recursiveSetInnerValues.push((innerValue: T) => { - // Set the inner value of the destructured value as the prop value p of the parent - recursiveSetInnerValue(Reflect.get(innerValue as object, p, innerValue)); - }); - - return recursiveProxy; - } - const innerTarget = target[SYM_PROXY_INNER_GET](); if (typeof innerTarget === "object" || typeof innerTarget === "function") { return Reflect.get(innerTarget, p, innerTarget); @@ -105,14 +86,8 @@ export function proxyInner( } }); - // Values destructured in the same tick the proxy was created will push their setInnerValue here - const recursiveSetInnerValues = [] as Array<(innerValue: T) => void>; - - // Once we set the parent inner value, we will call the setInnerValue functions of the destructured values, - // for them to get the proper value from the parent and use as their inner instead function setInnerValue(innerValue: T) { proxyDummy[SYM_PROXY_INNER_VALUE] = innerValue; - recursiveSetInnerValues.forEach(setInnerValue => setInnerValue(innerValue)); // Avoid binding toString if the inner value is null. // This can happen if we are setting the inner value as another instance of proxyInner, which will cause that proxy to instantly evaluate and throw an error diff --git a/src/webpack/api.tsx b/src/webpack/api.tsx index 7a27f7ff9..7beba1304 100644 --- a/src/webpack/api.tsx +++ b/src/webpack/api.tsx @@ -200,7 +200,7 @@ export function find(filter: FilterFn, parse: (mod: any) => any = if (typeof parse !== "function") throw new Error("Invalid find parse. Expected a function got " + typeof parse); - const [proxy, setInnerValue] = proxyInner(`Webpack find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find."); + const [proxy, setInnerValue] = proxyInner(`Webpack find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value."); waitFor(filter, m => setInnerValue(parse(m)), { isIndirect: true }); if (IS_REPORTER && !isIndirect) { @@ -448,7 +448,7 @@ export function mapMangledModule(code: string | string[], } } - const [proxy] = proxyInner(`Webpack mapMangledModule mapper filter matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find."); + const [proxy] = proxyInner(`Webpack mapMangledModule mapper filter matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value."); // Use the proxy to throw errors because no export matched the filter mapping[newName] = proxy; } @@ -469,7 +469,7 @@ export function mapMangledModule(code: string | string[], export function findModuleFactory(...code: string[]) { const filter = filters.byFactoryCode(...code); - const [proxy, setInnerValue] = proxyInner(`Webpack module factory find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value. This can happen if you try to destructure a primitive in the top level definition of the find."); + const [proxy, setInnerValue] = proxyInner(`Webpack module factory find matched no module. Filter: ${printFilter(filter)}`, "Webpack find with proxy called on a primitive value."); waitFor(filter, (_, { factory }) => setInnerValue(factory)); if (proxy[SYM_PROXY_INNER_VALUE] != null) return proxy[SYM_PROXY_INNER_VALUE] as ProxyInner;