revenge-bundle-next/lib/utils/src/discord.ts
PalmDevs c33086435e
feat(lib/modules/finders/filters): deprecate undefined and allow null in byDependencies
`null` is more correct semantically (and also shorter to type). `undefined` should only be module IDs that cannot be found, in which case, a warning log has been added.
2025-08-25 21:22:06 +07:00

154 lines
4.3 KiB
TypeScript

import { getAssetByName } from '@revenge-mod/assets'
import { TokensModuleId } from '@revenge-mod/discord/common'
import { lookupModule } from '@revenge-mod/modules/finders'
import {
byDependencies,
createFilterGenerator,
} from '@revenge-mod/modules/finders/filters'
import {
ReactJSXRuntimeModuleId,
ReactModuleId,
ReactNativeModuleId,
} from '@revenge-mod/react'
import type {
Filter,
FilterGenerator,
} from '@revenge-mod/modules/finders/filters'
import type { FC } from 'react'
// [React, ReactJsxRuntime, (Tokens), (BaseIconImage), (Asset), 2]
// Asset = relativeDep(1)
const IconComponentFilter = [
ReactModuleId,
ReactJSXRuntimeModuleId,
TokensModuleId,
null,
null,
2,
]
// Generated IconComponents that have multiple assets, there is no specific length, so the filter has to be generated on-the-fly.
// [React, ReactNative, ReactJsxRuntime, (Tokens), (BaseIconImage), (...Assets), 2]
// ...Assets = relativeDep(1..n)
const MultiIconComponentFilterBase = [
ReactModuleId,
ReactNativeModuleId,
ReactJSXRuntimeModuleId,
TokensModuleId,
null,
]
export type ByGeneratedIconComponent = FilterGenerator<
<N extends string>(
name: N,
...assets: string[]
) => Filter<{ [K in N]: FC<any> }>
>
/**
* Filter by icon component name and asset names.
*
* **Make sure to set `uninitialized: true` when using this filter in `lookupModule`!**
*
* @param names The component name, then the asset names if the component has multiple assets. *
* @example
* ```ts
* const [CopyIconModule] = lookupModule(
* byGeneratedIconComponent('CopyIcon'),
* {
* uninitialized: true,
* }
* )
* if (CopyIconModule) {
* const { CopyIcon } = CopyIconModule
* // Use CopyIcon as a React component
* }
* ```
* @example
* ```ts
* const [CircleXIconModule] = lookupModule(
* byGeneratedIconComponent(
* 'CircleXIcon',
* 'CircleXIcon-secondary',
* 'CircleXIcon-primary',
* ),
* {
* uninitialized: true,
* }
* )
* ```
*/
export const byGeneratedIconComponent = createFilterGenerator<
Parameters<ByGeneratedIconComponent>
>(
(names, id, exports) => {
if (typeof exports === 'object') {
if (typeof exports[names[0]] === 'function')
return Object.keys(exports).length === 1
} else {
let filter = IconComponentFilter
if (names.length > 1) {
const mids = []
for (let i = 1; i < names.length; i++) {
const name = names[i]
const mid = getAssetByName(name)?.moduleId
// Module ID can never be zero, so if it's falsy, it means the asset was not found.
if (!mid) return false
mids.push(mid)
}
filter = [...MultiIconComponentFilterBase, ...mids, 2]
} else {
const [name] = names
const mid = getAssetByName(name)?.moduleId
// Module ID can never be zero, so if it's falsy, it means the asset was not found.
if (!mid) return false
IconComponentFilter[4] = mid
}
return byDependencies(filter)(id, exports)
}
return false
},
names => `revenge.byGeneratedIconComponent(${names.join(',')})`,
) as ByGeneratedIconComponent
/**
* Looks up a generated icon component by its name and asset names.
*
* @param names The component name, then the asset names if the component has multiple assets.
* @returns The icon component, or `undefined` if it could not be found.
*/
export function lookupGeneratedIconComponent<N extends string>(
...names: [N, ...string[]]
) {
for (const name of names) {
let badFind = false
if (__DEV__) {
if (!getAssetByName(name)) {
badFind = true
warnUnregisteredAsset(name)
}
} else if (!getAssetByName(name)) return
if (__DEV__ && badFind) return
}
const [module] = lookupModule(byGeneratedIconComponent(...names), {
uninitialized: true,
})
return module?.[names[0]] as FC<any> | undefined
}
function warnUnregisteredAsset(name: string) {
nativeLoggingHook(
`\u001b[31mAsset "${name}" is not registered. Cannot get module ID to filter by.\u001b[0m`,
2,
)
}