revenge-bundle-next/lib/assets/src/index.ts
2025-07-05 13:56:52 +07:00

160 lines
4.1 KiB
TypeScript

import { Platform } from 'react-native'
import { aCustoms, aOverrides } from './_internal'
import { cache } from './caches'
import { AssetsRegistry } from './preinit'
import type {
Asset,
AssetId,
CustomAsset,
PackagerAsset,
RegisterableAsset,
} from './types'
export {
AssetsRegistry as AssetRegistry,
AssetsRegistryModuleId as AssetRegistryModuleId,
} from './preinit'
// iOS cannot display SVGs
let _preferredType: Asset['type'] = Platform.OS === 'ios' ? 'png' : 'svg'
/**
* Set the preferred asset type. This is used to determine which asset to use when multiple types are available.
*
* @param type The preferred asset type.
*/
export function setPreferredAssetType(type: Asset['type']) {
_preferredType = type
}
/**
* Yields all assets, both packager and custom.
*/
export function* getAssets(): Generator<Asset> {
yield* getPackagerAssets()
yield* getCustomAssets()
}
/**
* Yields all registered custom assets.
*/
export function* getCustomAssets(): Generator<CustomAsset> {
for (const asset of aCustoms) yield asset
}
/**
* Yields all registered packager assets, including ones with same name but different types.
*/
export function* getPackagerAssets(): Generator<PackagerAsset> {
for (const name in cache) {
const reg = cache[name]
for (const type in reg)
yield AssetsRegistry.getAssetByID(__r(reg[type]))
}
}
/**
* Get an asset by its name.
* If more than one asset is registered with the same name, this will return the one with the preferred type, or the first registered one.
*
* @param name The asset name.
* @param type The preferred asset type, defaults to the current preferred type.
*/
export function getAssetByName(
name: string,
type?: Asset['type'],
): Asset | undefined {
const id = getAssetIdByName(name, type)
if (id !== undefined) return AssetsRegistry.getAssetByID(id)
}
/**
* Gets all assets matching the name.
*
* @param name The asset name.
* @returns A record keyed by the type of the asset, with the value being the asset itself.
*/
export function getAssetsByName(
name: string,
): Record<Asset['type'], Asset> | undefined {
const reg = cache[name]
if (!reg) return
return Object.entries(reg).reduce(
(acc, [type, mid]) => {
acc[type as Asset['type']] = AssetsRegistry.getAssetByID(__r(mid))!
return acc
},
{} as Record<Asset['type'], Asset>,
)
}
/**
* Get an asset ID by its name.
* If more than one asset is registered with the same name, this will return the one with the preferred type, or the first registered one.
*
* @param name The asset name.
* @param type The preferred asset type, defaults to the current preferred type.
*/
export function getAssetIdByName(
name: string,
type?: Asset['type'],
): AssetId | undefined {
const reg = cache[name]
if (!reg) return
if (type) {
const mid = reg[type]
if (mid === undefined) return
return __r(mid)
}
let mid = reg[_preferredType]
if (mid === undefined)
for (const t in reg) {
mid = reg[t]
break
}
if (mid === undefined) return
return __r(mid)
}
/**
* Register an asset with the given name.
*
* @param asset The asset to register.
* @returns The asset ID.
*/
export function registerAsset(asset: RegisterableAsset): AssetId {
if (cache[asset.name]?.[asset.type] !== undefined)
throw new Error(
`Asset with name ${asset.name} and type ${asset.type} already exists!`,
)
aCustoms.add(asset as CustomAsset)
// @ts-expect-error
return AssetsRegistry.registerAsset(asset)
}
/**
* Override an asset with a custom asset.
*
* @param asset The asset to override.
* @param override The custom asset to override with.
*/
export function addAssetOverride(asset: Asset, override: Asset) {
aOverrides.set(asset, override)
}
/**
* Remove an asset override.
*
* @param asset The asset to remove the override for.
* @returns The asset that was removed.
*/
export function removeAssetOverride(asset: Asset) {
return aOverrides.delete(asset)
}