2024-05-03 02:18:12 +00:00
/ *
* Vencord , a Discord client mod
2024-05-26 23:41:28 +00:00
* Copyright ( c ) 2024 Vendicated , Nuckyz and contributors
2024-05-03 02:18:12 +00:00
* SPDX - License - Identifier : GPL - 3.0 - or - later
* /
2024-05-20 02:01:08 +00:00
import { UNCONFIGURABLE_PROPERTIES } from "./misc" ;
2024-05-11 04:11:57 +00:00
import { AnyObject } from "./types" ;
export type ProxyInner < T = AnyObject > = T & {
2024-05-28 20:41:34 +00:00
[ SYM_PROXY_INNER_GET ] ? : ( ) = > T ;
[ SYM_PROXY_INNER_VALUE ] ? : T | undefined ;
2024-05-11 04:11:57 +00:00
} ;
2024-05-28 20:41:34 +00:00
export const SYM_PROXY_INNER_GET = Symbol . for ( "vencord.proxyInner.get" ) ;
export const SYM_PROXY_INNER_VALUE = Symbol . for ( "vencord.proxyInner.innerValue" ) ;
2024-05-03 02:18:12 +00:00
const handler : ProxyHandler < any > = {
. . . Object . fromEntries ( Object . getOwnPropertyNames ( Reflect ) . map ( propName = >
2024-05-28 20:41:34 +00:00
[ propName , ( target : any , . . . args : any [ ] ) = > Reflect [ propName ] ( target [ SYM_PROXY_INNER_GET ] ( ) , . . . args ) ]
2024-05-03 02:18:12 +00:00
) ) ,
2024-05-24 01:52:32 +00:00
set : ( target , p , value ) = > {
2024-05-28 20:41:34 +00:00
const innerTarget = target [ SYM_PROXY_INNER_GET ] ( ) ;
2024-05-24 01:52:32 +00:00
return Reflect . set ( innerTarget , p , value , innerTarget ) ;
} ,
2024-05-03 02:18:12 +00:00
ownKeys : target = > {
2024-05-28 20:41:34 +00:00
const keys = Reflect . ownKeys ( target [ SYM_PROXY_INNER_GET ] ( ) ) ;
2024-05-20 02:01:08 +00:00
for ( const key of UNCONFIGURABLE_PROPERTIES ) {
2024-05-03 02:18:12 +00:00
if ( ! keys . includes ( key ) ) keys . push ( key ) ;
}
return keys ;
} ,
getOwnPropertyDescriptor : ( target , p ) = > {
2024-06-22 09:16:36 +00:00
if ( typeof p === "string" && UNCONFIGURABLE_PROPERTIES . includes ( p ) ) {
2024-05-03 02:18:12 +00:00
return Reflect . getOwnPropertyDescriptor ( target , p ) ;
2024-06-22 08:50:09 +00:00
}
2024-05-03 02:18:12 +00:00
2024-05-28 20:41:34 +00:00
const descriptor = Reflect . getOwnPropertyDescriptor ( target [ SYM_PROXY_INNER_GET ] ( ) , p ) ;
2024-05-03 02:18:12 +00:00
if ( descriptor ) Object . defineProperty ( target , p , descriptor ) ;
return descriptor ;
}
} ;
/ * *
* 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 .
2024-05-30 02:42:14 +00:00
*
2024-06-27 09:01:13 +00:00
* IMPORTANT :
* Destructuring at top level is not supported for proxyInner .
*
2024-05-04 20:49:20 +00:00
* @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
2024-05-03 02:18:12 +00:00
* @returns A proxy which will act like the inner value when accessed
* /
2024-05-11 04:11:57 +00:00
export function proxyInner < T = AnyObject > (
2024-05-04 20:49:20 +00:00
errMsg = "Proxy inner value is undefined, setInnerValue was never called." ,
2024-06-27 09:01:13 +00:00
primitiveErrMsg = "proxyInner called on a primitive value."
2024-05-11 04:11:57 +00:00
) : [ proxy : ProxyInner < T > , setInnerValue : ( innerValue : T ) = > void ] {
2024-06-22 09:14:43 +00:00
const proxyDummy = Object . assign ( function ( ) { } , {
2024-05-28 20:41:34 +00:00
[ SYM_PROXY_INNER_GET ] : function ( ) {
if ( proxyDummy [ SYM_PROXY_INNER_VALUE ] == null ) {
2024-05-04 20:49:20 +00:00
throw new Error ( errMsg ) ;
2024-05-03 02:18:12 +00:00
}
2024-05-28 20:41:34 +00:00
return proxyDummy [ SYM_PROXY_INNER_VALUE ] ;
2024-05-03 02:18:12 +00:00
} ,
2024-05-28 20:41:34 +00:00
[ SYM_PROXY_INNER_VALUE ] : void 0 as T | undefined
2024-05-03 02:18:12 +00:00
} ) ;
2024-05-24 01:20:24 +00:00
const proxy = new Proxy ( proxyDummy , {
2024-05-03 02:18:12 +00:00
. . . handler ,
2024-05-28 20:41:34 +00:00
get ( target , p , receiver ) {
if ( p === SYM_PROXY_INNER_GET || p === SYM_PROXY_INNER_VALUE ) {
return Reflect . get ( target , p , receiver ) ;
}
2024-05-03 02:18:12 +00:00
2024-05-28 20:41:34 +00:00
const innerTarget = target [ SYM_PROXY_INNER_GET ] ( ) ;
2024-05-03 02:18:12 +00:00
if ( typeof innerTarget === "object" || typeof innerTarget === "function" ) {
2024-05-24 01:51:23 +00:00
return Reflect . get ( innerTarget , p , innerTarget ) ;
2024-05-03 02:18:12 +00:00
}
2024-05-04 20:49:20 +00:00
throw new Error ( primitiveErrMsg ) ;
2024-05-03 02:18:12 +00:00
}
2024-05-24 01:20:24 +00:00
} ) ;
function setInnerValue ( innerValue : T ) {
2024-05-28 20:41:34 +00:00
proxyDummy [ SYM_PROXY_INNER_VALUE ] = innerValue ;
2024-05-03 02:18:12 +00:00
2024-06-22 01:54:08 +00:00
// 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
2024-06-23 22:48:15 +00:00
if ( typeof innerValue === "function" && innerValue [ SYM_PROXY_INNER_VALUE ] == null ) {
2024-05-24 01:20:24 +00:00
proxy . toString = innerValue . toString . bind ( innerValue ) ;
2024-05-03 02:18:12 +00:00
}
2024-05-24 01:20:24 +00:00
}
return [ proxy , setInnerValue ] ;
2024-05-03 02:18:12 +00:00
}