2022-10-21 23:17:06 +00:00
/ *
* Vencord , a modification for Discord ' s desktop app
* Copyright ( c ) 2022 Vendicated and contributors
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < https : / / www.gnu.org / licenses / > .
* /
2023-05-05 23:36:00 +00:00
import { proxyLazy } from "@utils/lazy" ;
2023-11-23 05:43:22 +00:00
import { LazyComponent } from "@utils/lazyReact" ;
2023-05-05 23:36:00 +00:00
import { Logger } from "@utils/Logger" ;
2023-11-27 05:56:57 +00:00
import { canonicalizeMatch } from "@utils/patches" ;
2022-09-05 17:54:02 +00:00
import type { WebpackInstance } from "discord-types/other" ;
2022-10-22 16:18:41 +00:00
2022-11-07 20:05:33 +00:00
import { traceFunction } from "../debug/Tracer" ;
2022-09-05 17:54:02 +00:00
2022-11-03 18:12:50 +00:00
const logger = new Logger ( "Webpack" ) ;
2022-09-30 22:42:50 +00:00
export let _resolveReady : ( ) = > void ;
/ * *
* Fired once a gateway connection to Discord has been established .
* This indicates that the core webpack module s have been initialised
* /
export const onceReady = new Promise < void > ( r = > _resolveReady = r ) ;
2022-09-05 17:54:02 +00:00
export let wreq : WebpackInstance ;
export let cache : WebpackInstance [ "c" ] ;
2022-08-31 18:47:07 +00:00
export type FilterFn = ( mod : any ) = > boolean ;
export const filters = {
2022-10-30 19:45:18 +00:00
byProps : ( . . . props : string [ ] ) : FilterFn = >
2022-08-31 18:47:07 +00:00
props . length === 1
? m = > m [ props [ 0 ] ] !== void 0
: m = > props . every ( p = > m [ p ] !== void 0 ) ,
2022-10-30 19:45:18 +00:00
2022-09-27 14:57:46 +00:00
byCode : ( . . . code : string [ ] ) : FilterFn = > m = > {
if ( typeof m !== "function" ) return false ;
const s = Function . prototype . toString . call ( m ) ;
for ( const c of code ) {
if ( ! s . includes ( c ) ) return false ;
}
return true ;
2022-09-28 10:15:30 +00:00
} ,
2023-02-10 21:33:34 +00:00
byStoreName : ( name : string ) : FilterFn = > m = >
2023-11-23 01:44:04 +00:00
m . constructor ? . displayName === name ,
componentByCode : ( . . . code : string [ ] ) : FilterFn = > {
const filter = filters . byCode ( . . . code ) ;
return m = > {
if ( filter ( m ) ) return true ;
if ( ! m . $ $typeof ) return false ;
2024-03-08 03:23:35 +00:00
if ( m . type && m . type . render ) return filter ( m . type . render ) ; // memo + forwardRef
2023-11-23 01:44:04 +00:00
if ( m . type ) return filter ( m . type ) ; // memos
if ( m . render ) return filter ( m . render ) ; // forwardRefs
return false ;
} ;
}
2022-08-31 18:47:07 +00:00
} ;
export const subscriptions = new Map < FilterFn , CallbackFn > ( ) ;
export const listeners = new Set < CallbackFn > ( ) ;
2023-11-27 05:56:57 +00:00
export type CallbackFn = ( mod : any , id : string ) = > void ;
2022-08-31 18:47:07 +00:00
export function _initWebpack ( instance : typeof window . webpackChunkdiscord_app ) {
2022-09-05 17:54:02 +00:00
if ( cache !== void 0 ) throw "no." ;
2022-08-31 18:47:07 +00:00
2023-10-24 22:17:11 +00:00
instance . push ( [ [ Symbol ( "Vencord" ) ] , { } , r = > wreq = r ] ) ;
2023-10-26 20:51:03 +00:00
instance . pop ( ) ;
2023-10-24 22:17:11 +00:00
if ( ! wreq ) return false ;
2022-09-05 17:54:02 +00:00
cache = wreq . c ;
2023-10-24 22:17:11 +00:00
return true ;
2022-08-31 18:47:07 +00:00
}
2024-02-29 23:18:09 +00:00
let devToolsOpen = false ;
2023-04-03 23:16:29 +00:00
if ( IS_DEV && IS_DISCORD_DESKTOP ) {
2022-11-03 19:36:17 +00:00
// At this point in time, DiscordNative has not been exposed yet, so setImmediate is needed
setTimeout ( ( ) = > {
DiscordNative /* just to make sure */ ? . window . setDevtoolsCallbacks ( ( ) = > devToolsOpen = true , ( ) = > devToolsOpen = false ) ;
} , 0 ) ;
}
2023-09-25 16:27:18 +00:00
function handleModuleNotFound ( method : string , . . . filter : unknown [ ] ) {
const err = new Error ( ` webpack. ${ method } found no module ` ) ;
logger . error ( err , "Filter:" , filter ) ;
// Strict behaviour in DevBuilds to fail early and make sure the issue is found
if ( IS_DEV && ! devToolsOpen )
throw err ;
}
2022-11-25 18:25:35 +00:00
/ * *
* Find the first module that matches the filter
* /
2023-09-25 16:27:18 +00:00
export const find = traceFunction ( "find" , function find ( filter : FilterFn , { isIndirect = false , isWaitFor = false } : { isIndirect? : boolean ; isWaitFor? : boolean ; } = { } ) {
2022-08-31 18:47:07 +00:00
if ( typeof filter !== "function" )
2022-10-01 00:27:28 +00:00
throw new Error ( "Invalid filter. Expected a function got " + typeof filter ) ;
2022-08-31 18:47:07 +00:00
2022-09-05 17:54:02 +00:00
for ( const key in cache ) {
const mod = cache [ key ] ;
2024-03-27 20:27:56 +00:00
if ( ! mod ? . exports || mod . exports === window ) continue ;
2022-09-27 12:34:57 +00:00
2023-03-08 04:59:50 +00:00
if ( filter ( mod . exports ) ) {
2023-11-27 05:56:57 +00:00
return isWaitFor ? [ mod . exports , key ] : mod . exports ;
2023-03-08 04:59:50 +00:00
}
2022-09-28 20:49:46 +00:00
2024-03-27 20:27:56 +00:00
if ( mod . exports . default && mod . exports . default !== window && filter ( mod . exports . default ) ) {
2023-09-25 16:27:18 +00:00
const found = mod . exports . default ;
2023-11-27 05:56:57 +00:00
return isWaitFor ? [ found , key ] : found ;
2023-03-08 04:59:50 +00:00
}
2022-08-31 18:47:07 +00:00
}
2023-09-25 16:27:18 +00:00
if ( ! isIndirect ) {
handleModuleNotFound ( "find" , filter ) ;
2022-10-30 19:45:18 +00:00
}
2023-03-08 04:59:50 +00:00
return isWaitFor ? [ null , null ] : null ;
2022-11-07 20:05:33 +00:00
} ) ;
2022-08-31 18:47:07 +00:00
2023-09-25 16:27:18 +00:00
export function findAll ( filter : FilterFn ) {
2022-10-30 19:45:18 +00:00
if ( typeof filter !== "function" )
throw new Error ( "Invalid filter. Expected a function got " + typeof filter ) ;
2022-08-31 18:47:07 +00:00
const ret = [ ] as any [ ] ;
2022-09-05 17:54:02 +00:00
for ( const key in cache ) {
const mod = cache [ key ] ;
2022-09-30 22:42:50 +00:00
if ( ! mod ? . exports ) continue ;
if ( filter ( mod . exports ) )
ret . push ( mod . exports ) ;
if ( mod . exports . default && filter ( mod . exports . default ) )
2023-09-25 16:27:18 +00:00
ret . push ( mod . exports . default ) ;
2022-08-31 18:47:07 +00:00
}
return ret ;
}
2022-10-14 19:34:35 +00:00
/ * *
2022-11-03 18:12:50 +00:00
* Same as { @link find } but in bulk
2022-11-15 23:40:46 +00:00
* @param filterFns Array of filters . Please note that this array will be modified in place , so if you still
2022-11-03 18:12:50 +00:00
* need it afterwards , pass a copy .
* @returns Array of results in the same order as the passed filters
* /
2022-11-15 23:40:46 +00:00
export const findBulk = traceFunction ( "findBulk" , function findBulk ( . . . filterFns : FilterFn [ ] ) {
2022-11-03 18:12:50 +00:00
if ( ! Array . isArray ( filterFns ) )
throw new Error ( "Invalid filters. Expected function[] got " + typeof filterFns ) ;
2022-10-14 19:34:35 +00:00
2022-11-03 18:12:50 +00:00
const { length } = filterFns ;
if ( length === 0 )
throw new Error ( "Expected at least two filters." ) ;
if ( length === 1 ) {
if ( IS_DEV ) {
throw new Error ( "bulk called with only one filter. Use find" ) ;
}
return find ( filterFns [ 0 ] ) ;
}
const filters = filterFns as Array < FilterFn | undefined > ;
let found = 0 ;
const results = Array ( length ) ;
outer :
for ( const key in cache ) {
const mod = cache [ key ] ;
if ( ! mod ? . exports ) continue ;
for ( let j = 0 ; j < length ; j ++ ) {
const filter = filters [ j ] ;
// Already done
if ( filter === undefined ) continue ;
if ( filter ( mod . exports ) ) {
results [ j ] = mod . exports ;
filters [ j ] = undefined ;
if ( ++ found === length ) break outer ;
break ;
}
if ( mod . exports . default && filter ( mod . exports . default ) ) {
results [ j ] = mod . exports . default ;
filters [ j ] = undefined ;
if ( ++ found === length ) break outer ;
break ;
}
2022-10-14 19:34:35 +00:00
}
}
2022-11-03 18:12:50 +00:00
if ( found !== length ) {
const err = new Error ( ` Got ${ length } filters, but only found ${ found } modules! ` ) ;
if ( IS_DEV ) {
2022-11-03 19:36:17 +00:00
if ( ! devToolsOpen )
// Strict behaviour in DevBuilds to fail early and make sure the issue is found
throw err ;
} else {
logger . warn ( err ) ;
2022-11-03 18:12:50 +00:00
}
}
return results ;
2022-11-15 23:40:46 +00:00
} ) ;
2022-11-03 18:12:50 +00:00
/ * *
2023-11-27 05:56:57 +00:00
* Find the id of the first module factory that includes all the given code
* @returns string or null
2022-11-03 18:12:50 +00:00
* /
2023-11-27 05:56:57 +00:00
export const findModuleId = traceFunction ( "findModuleId" , function findModuleId ( . . . code : string [ ] ) {
outer :
2022-11-03 18:12:50 +00:00
for ( const id in wreq . m ) {
2023-11-27 05:56:57 +00:00
const str = wreq . m [ id ] . toString ( ) ;
for ( const c of code ) {
if ( ! str . includes ( c ) ) continue outer ;
2022-11-03 18:12:50 +00:00
}
2023-11-27 05:56:57 +00:00
return id ;
2022-11-03 18:12:50 +00:00
}
2022-10-30 19:45:18 +00:00
2023-11-27 05:56:57 +00:00
const err = new Error ( "Didn't find module with code(s):\n" + code . join ( "\n" ) ) ;
2022-11-03 18:12:50 +00:00
if ( IS_DEV ) {
2022-11-03 19:36:17 +00:00
if ( ! devToolsOpen )
// Strict behaviour in DevBuilds to fail early and make sure the issue is found
throw err ;
} else {
logger . warn ( err ) ;
2022-11-03 18:12:50 +00:00
}
return null ;
2022-11-07 20:05:33 +00:00
} ) ;
2022-11-03 18:12:50 +00:00
2023-11-27 05:56:57 +00:00
/ * *
* Find the first module factory that includes all the given code
* @returns The module factory or null
* /
export function findModuleFactory ( . . . code : string [ ] ) {
const id = findModuleId ( . . . code ) ;
if ( ! id ) return null ;
return wreq . m [ id ] ;
}
export const lazyWebpackSearchHistory = [ ] as Array < [ "find" | "findByProps" | "findByCode" | "findStore" | "findComponent" | "findComponentByCode" | "findExportedComponent" | "waitFor" | "waitForComponent" | "waitForStore" | "proxyLazyWebpack" | "LazyComponentWebpack" | "extractAndLoadChunks" , any [ ] ] > ;
2023-11-25 00:32:21 +00:00
/ * *
* This is just a wrapper around { @link proxyLazy } to make our reporter test for your webpack finds .
*
* Wraps the result of { @link makeLazy } in a Proxy you can consume as if it wasn ' t lazy .
* On first property access , the lazy is evaluated
* @param factory lazy factory
* @param attempts how many times to try to evaluate the lazy before giving up
* @returns Proxy
*
* Note that the example below exists already as an api , see { @link findByPropsLazy }
* @example const mod = proxyLazy ( ( ) = > findByProps ( "blah" ) ) ; console . log ( mod . blah ) ;
* /
export function proxyLazyWebpack < T = any > ( factory : ( ) = > any , attempts? : number ) {
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "proxyLazyWebpack" , [ factory ] ] ) ;
return proxyLazy < T > ( factory , attempts ) ;
}
/ * *
* This is just a wrapper around { @link LazyComponent } to make our reporter test for your webpack finds .
*
* A lazy component . The factory method is called on first render .
* @param factory Function returning a Component
* @param attempts How many times to try to get the component before giving up
* @returns Result of factory function
* /
export function LazyComponentWebpack < T extends object = any > ( factory : ( ) = > any , attempts? : number ) {
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "LazyComponentWebpack" , [ factory ] ] ) ;
return LazyComponent < T > ( factory , attempts ) ;
}
/ * *
2023-11-27 05:56:57 +00:00
* Find the first module that matches the filter , lazily
2023-11-25 00:32:21 +00:00
* /
export function findLazy ( filter : FilterFn ) {
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "find" , [ filter ] ] ) ;
return proxyLazy ( ( ) = > find ( filter ) ) ;
}
2022-11-25 18:25:35 +00:00
/ * *
* Find the first module that has the specified properties
* /
2022-08-31 18:47:07 +00:00
export function findByProps ( . . . props : string [ ] ) {
2023-09-25 16:27:18 +00:00
const res = find ( filters . byProps ( . . . props ) , { isIndirect : true } ) ;
if ( ! res )
handleModuleNotFound ( "findByProps" , . . . props ) ;
return res ;
2022-08-31 18:47:07 +00:00
}
2022-11-28 12:37:55 +00:00
/ * *
2023-11-27 05:56:57 +00:00
* Find the first module that has the specified properties , lazily
2022-11-28 12:37:55 +00:00
* /
export function findByPropsLazy ( . . . props : string [ ] ) {
2023-11-25 00:32:21 +00:00
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "findByProps" , props ] ) ;
2023-09-25 16:27:18 +00:00
return proxyLazy ( ( ) = > findByProps ( . . . props ) ) ;
2022-11-28 12:37:55 +00:00
}
2022-11-25 18:25:35 +00:00
/ * *
2023-11-27 05:56:57 +00:00
* Find the first function that includes all the given code
2022-11-25 18:25:35 +00:00
* /
2022-11-06 17:37:01 +00:00
export function findByCode ( . . . code : string [ ] ) {
2023-09-25 16:27:18 +00:00
const res = find ( filters . byCode ( . . . code ) , { isIndirect : true } ) ;
if ( ! res )
handleModuleNotFound ( "findByCode" , . . . code ) ;
return res ;
2022-11-06 17:37:01 +00:00
}
2022-11-28 12:37:55 +00:00
/ * *
2023-11-27 05:56:57 +00:00
* Find the first function that includes all the given code , lazily
2022-11-28 12:37:55 +00:00
* /
export function findByCodeLazy ( . . . code : string [ ] ) {
2023-11-25 00:32:21 +00:00
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "findByCode" , code ] ) ;
2023-09-25 16:27:18 +00:00
return proxyLazy ( ( ) = > findByCode ( . . . code ) ) ;
2022-11-28 12:37:55 +00:00
}
2023-02-08 20:48:26 +00:00
/ * *
* Find a store by its displayName
* /
2023-02-10 21:33:34 +00:00
export function findStore ( name : string ) {
2023-09-25 16:27:18 +00:00
const res = find ( filters . byStoreName ( name ) , { isIndirect : true } ) ;
if ( ! res )
handleModuleNotFound ( "findStore" , name ) ;
return res ;
2023-02-08 20:48:26 +00:00
}
/ * *
2023-11-27 05:56:57 +00:00
* Find a store by its displayName , lazily
2023-02-08 20:48:26 +00:00
* /
2023-02-10 21:33:34 +00:00
export function findStoreLazy ( name : string ) {
2023-11-25 00:32:21 +00:00
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "findStore" , [ name ] ] ) ;
2023-09-25 16:27:18 +00:00
return proxyLazy ( ( ) = > findStore ( name ) ) ;
2023-02-08 20:48:26 +00:00
}
2023-11-22 06:04:17 +00:00
/ * *
* Finds the component which includes all the given code . Checks for plain components , memos and forwardRefs
* /
export function findComponentByCode ( . . . code : string [ ] ) {
2023-11-23 01:44:04 +00:00
const res = find ( filters . componentByCode ( . . . code ) , { isIndirect : true } ) ;
2023-11-23 01:20:02 +00:00
if ( ! res )
handleModuleNotFound ( "findComponentByCode" , . . . code ) ;
return res ;
2023-11-22 06:04:17 +00:00
}
/ * *
* Finds the first component that matches the filter , lazily .
* /
export function findComponentLazy < T extends object = any > ( filter : FilterFn ) {
2023-11-25 00:32:21 +00:00
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "findComponent" , [ filter ] ] ) ;
2023-11-27 05:56:57 +00:00
return LazyComponent < T > ( ( ) = > {
const res = find ( filter , { isIndirect : true } ) ;
if ( ! res )
handleModuleNotFound ( "findComponent" , filter ) ;
return res ;
} ) ;
2023-11-22 06:04:17 +00:00
}
/ * *
* Finds the first component that includes all the given code , lazily
* /
export function findComponentByCodeLazy < T extends object = any > ( . . . code : string [ ] ) {
2023-11-25 00:32:21 +00:00
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "findComponentByCode" , code ] ) ;
2023-11-27 05:56:57 +00:00
return LazyComponent < T > ( ( ) = > {
const res = find ( filters . componentByCode ( . . . code ) , { isIndirect : true } ) ;
if ( ! res )
handleModuleNotFound ( "findComponentByCode" , . . . code ) ;
return res ;
} ) ;
2023-11-22 06:04:17 +00:00
}
/ * *
* Finds the first component that is exported by the first prop name , lazily
* /
export function findExportedComponentLazy < T extends object = any > ( . . . props : string [ ] ) {
2023-11-25 00:32:21 +00:00
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "findExportedComponent" , props ] ) ;
2023-11-27 05:56:57 +00:00
return LazyComponent < T > ( ( ) = > {
const res = find ( filters . byProps ( . . . props ) , { isIndirect : true } ) ;
if ( ! res )
handleModuleNotFound ( "findExportedComponent" , . . . props ) ;
return res [ props [ 0 ] ] ;
} ) ;
}
2024-04-14 00:12:25 +00:00
const DefaultExtractAndLoadChunksRegex = /(?:Promise\.all\((\[\i\.\i\(".+?"\).+?\])\)|Promise\.resolve\(\)).then\(\i\.bind\(\i,"(.+?)"\)\)/ ;
2023-11-27 05:56:57 +00:00
/ * *
* Extract and load chunks using their entry point
2024-03-27 20:44:41 +00:00
* @param code An array of all the code the module factory containing the lazy chunk loading must include
* @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second . Defaults to a matcher that captures the lazy chunk loading found in the module factory
* @returns A promise that resolves when the chunks were loaded
2023-11-27 05:56:57 +00:00
* /
2024-04-14 00:12:25 +00:00
export async function extractAndLoadChunks ( code : string [ ] , matcher : RegExp = DefaultExtractAndLoadChunksRegex ) {
2023-11-27 05:56:57 +00:00
const module = findModuleFactory ( . . . code ) ;
if ( ! module ) {
const err = new Error ( "extractAndLoadChunks: Couldn't find module factory" ) ;
logger . warn ( err , "Code:" , code , "Matcher:" , matcher ) ;
return ;
}
const match = module .toString ( ) . match ( canonicalizeMatch ( matcher ) ) ;
if ( ! match ) {
const err = new Error ( "extractAndLoadChunks: Couldn't find entry point id in module factory code" ) ;
logger . warn ( err , "Code:" , code , "Matcher:" , matcher ) ;
// Strict behaviour in DevBuilds to fail early and make sure the issue is found
if ( IS_DEV && ! devToolsOpen )
throw err ;
return ;
}
2024-03-27 20:44:41 +00:00
const [ , rawChunkIds , entryPointId ] = match ;
2024-04-14 00:12:25 +00:00
if ( Number . isNaN ( entryPointId ) ) {
2024-03-27 20:44:41 +00:00
const err = new Error ( "extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number" ) ;
2023-11-27 05:56:57 +00:00
logger . warn ( err , "Code:" , code , "Matcher:" , matcher ) ;
// Strict behaviour in DevBuilds to fail early and make sure the issue is found
if ( IS_DEV && ! devToolsOpen )
throw err ;
return ;
}
2024-04-14 00:12:25 +00:00
if ( rawChunkIds ) {
const chunkIds = Array . from ( rawChunkIds . matchAll ( /\("(.+?)"\)/g ) ) . map ( ( m : any ) = > m [ 1 ] ) ;
await Promise . all ( chunkIds . map ( id = > wreq . e ( id ) ) ) ;
}
2024-03-27 20:44:41 +00:00
wreq ( entryPointId ) ;
2023-11-27 05:56:57 +00:00
}
/ * *
* This is just a wrapper around { @link extractAndLoadChunks } to make our reporter test for your webpack finds .
*
* Extract and load chunks using their entry point
2024-03-27 20:44:41 +00:00
* @param code An array of all the code the module factory containing the lazy chunk loading must include
* @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second . Defaults to a matcher that captures the lazy chunk loading found in the module factory
* @returns A function that returns a promise that resolves when the chunks were loaded , on first call
2023-11-27 05:56:57 +00:00
* /
2024-04-14 00:12:25 +00:00
export function extractAndLoadChunksLazy ( code : string [ ] , matcher = DefaultExtractAndLoadChunksRegex ) {
2023-11-27 05:56:57 +00:00
if ( IS_DEV ) lazyWebpackSearchHistory . push ( [ "extractAndLoadChunks" , [ code , matcher ] ] ) ;
return ( ) = > extractAndLoadChunks ( code , matcher ) ;
2023-11-22 06:04:17 +00:00
}
2022-11-25 18:25:35 +00:00
/ * *
* Wait for a module that matches the provided filter to be registered ,
* then call the callback with the module as the first argument
* /
2023-11-25 00:32:21 +00:00
export function waitFor ( filter : string | string [ ] | FilterFn , callback : CallbackFn , { isIndirect = false } : { isIndirect? : boolean ; } = { } ) {
if ( IS_DEV && ! isIndirect ) lazyWebpackSearchHistory . push ( [ "waitFor" , Array . isArray ( filter ) ? filter : [ filter ] ] ) ;
2022-10-30 19:45:18 +00:00
if ( typeof filter === "string" )
filter = filters . byProps ( filter ) ;
else if ( Array . isArray ( filter ) )
filter = filters . byProps ( . . . filter ) ;
else if ( typeof filter !== "function" )
throw new Error ( "filter must be a string, string[] or function, got " + typeof filter ) ;
2024-03-07 12:36:59 +00:00
if ( cache != null ) {
const [ existing , id ] = find ( filter , { isIndirect : true , isWaitFor : true } ) ;
if ( existing ) return void callback ( existing , id ) ;
}
2023-11-23 05:45:01 +00:00
2022-08-31 18:47:07 +00:00
subscriptions . set ( filter , callback ) ;
}
export function addListener ( callback : CallbackFn ) {
listeners . add ( callback ) ;
}
export function removeListener ( callback : CallbackFn ) {
listeners . delete ( callback ) ;
2022-09-16 19:43:38 +00:00
}
/ * *
2022-11-03 18:12:50 +00:00
* Search module s by keyword . This searches the factory methods ,
* meaning you can search all sorts of things , displayName , methodName , strings somewhere in the code , etc
* @param filters One or more strings or regexes
* @returns Mapping of found module s
* /
2022-09-16 19:43:38 +00:00
export function search ( . . . filters : Array < string | RegExp > ) {
const results = { } as Record < number , Function > ;
const factories = wreq . m ;
outer :
for ( const id in factories ) {
2022-10-01 23:05:15 +00:00
const factory = factories [ id ] . original ? ? factories [ id ] ;
2022-09-16 19:43:38 +00:00
const str : string = factory . toString ( ) ;
for ( const filter of filters ) {
if ( typeof filter === "string" && ! str . includes ( filter ) ) continue outer ;
if ( filter instanceof RegExp && ! filter . test ( str ) ) continue outer ;
}
results [ id ] = factory ;
}
return results ;
}
/ * *
2022-11-03 18:12:50 +00:00
* Extract a specific module by id into its own Source File . This has no effect on
* the code , it is only useful to be able to look at a specific module without having
* to view a massive file . extract then returns the extracted module so you can jump to it .
* As mentioned above , note that this extracted module is not actually used ,
* so putting breakpoints or similar will have no effect .
* @param id The id of the module to extract
* /
2023-11-27 05:56:57 +00:00
export function extract ( id : string | number ) {
2022-09-16 19:43:38 +00:00
const mod = wreq . m [ id ] as Function ;
if ( ! mod ) return null ;
const code = `
// [EXTRACTED] WebpackModule${id}
// WARNING: This module was extracted to be more easily readable.
// This module is NOT ACTUALLY USED! This means putting breakpoints will have NO EFFECT!!
2023-10-25 13:28:50 +00:00
0 , $ { mod . toString ( ) }
2022-09-16 19:43:38 +00:00
//# sourceURL=ExtractedWebpackModule${id}
` ;
const extracted = ( 0 , eval ) ( code ) ;
return extracted as Function ;
2022-09-16 20:59:34 +00:00
}