@applicaster/zapp-react-native-utils
Version:
Applicaster Zapp React Native utilities package
257 lines (223 loc) • 7.17 kB
text/typescript
import * as R from "ramda";
import { toCamelCase, toPascalCase } from "../stringUtils";
import { getNavigationType } from "../navigationUtils";
import { deprecationMessage } from "../appUtils";
import { pluginUtilsLogger } from "./logger";
import { platformSelect } from "../reactUtils";
type PluginModule = any;
type Plugin = {
module: PluginModule;
type: string;
name: string;
identifier: string;
configuration: any;
};
/**
* returns the component module for a specific type
* Will look in components first, then in plugins
*/
export function getComponentModule({
componentType,
components,
plugins,
}: {
componentType: string;
components: ComponentsMap;
plugins: Plugin[] | QuickBrickPlugin[];
}) {
const component = R.compose(
R.prop(R.__, components),
toPascalCase
)(componentType);
if (component) {
return component;
}
return R.compose(
R.prop("module"),
R.defaultTo({}),
R.find(R.propEq("identifier", componentType))
)(plugins);
}
/**
* returns the component if it exists, returns undefined otherwise. also decorates
* the component with the decorators if provided.
*/
export function findComponentByType({
componentType,
components,
decorators = R.identity,
plugins = [],
}) {
const applyDecorators = Array.isArray(decorators)
? R.compose(...R.reverse(decorators))
: decorators;
const component = getComponentModule({ componentType, components, plugins });
return R.unless(R.isNil, applyDecorators)(component);
}
/**
* Returns the plugin for a given identifier, if found
* @param identifier of the plugin to look for
* @param plugins map of the available plugins
* @param doNotWarn if set to true, will not log a warning if plugin is not found
* @return whole plugin if found, undefined otherwise
*/
export function findPluginByIdentifier(
identifier: string,
plugins: (QuickBrickPlugin | ZappPlugin | Plugin)[],
doNotWarn: boolean = false
): (QuickBrickPlugin | ZappPlugin | Plugin) | undefined {
if (!identifier) {
return undefined;
}
const plugin = R.compose(
R.find(R.propEq("identifier", identifier)),
R.values
)(plugins);
if (!plugin && identifier !== "river" && identifier !== "hooks") {
if (!doNotWarn) {
pluginUtilsLogger.warning({
message: `Could not find plugin for identifier ${identifier}`,
data: { identifier },
});
}
}
return plugin;
}
const pluginTypeForItemTypeMap = {
playable: "player",
};
/**
* return the type of plugin required for a type of item
* when names don't match (see map above)
* @param itemType requested
* @returns matching result in the map above. returns the input otherwise
*/
function pluginTypeForItemTypeMapper(itemType) {
return R.when(
R.has(R.__, pluginTypeForItemTypeMap),
R.prop(R.__, pluginTypeForItemTypeMap)
)(itemType);
}
/**
* returns the plugin module for a given type, if found
* @param type of the plugin to look for
* @param plugins map of the available plugins
* @param returnFullObject if needed to return full instance of plugin (optional)
* @return plugin module or whole plugin found, if any, undefined otherwise
*/
export function findPluginByType(
type: string,
plugins: (QuickBrickPlugin | Plugin)[],
optionsOrReturnFullObject?:
| { returnFullObject?: boolean; skipWarning?: boolean }
| boolean
): PluginModule | (QuickBrickPlugin | Plugin) {
let returnFullObject;
let skipWarning = false;
if (typeof optionsOrReturnFullObject === "boolean") {
returnFullObject = optionsOrReturnFullObject;
} else if (typeof optionsOrReturnFullObject === "object") {
if (optionsOrReturnFullObject.skipWarning) {
skipWarning = optionsOrReturnFullObject.skipWarning;
}
if (optionsOrReturnFullObject?.returnFullObject) {
returnFullObject = optionsOrReturnFullObject.returnFullObject;
}
}
const plugin =
R.compose(
R.find(R.propEq("type", pluginTypeForItemTypeMapper(type))),
R.values
)(plugins) || {};
const { module: pluginModule, configuration } = plugin;
if (returnFullObject) {
return plugin;
}
if (!pluginModule) {
if (type !== "river" && type !== "hooks" && !skipWarning) {
pluginUtilsLogger.warning({
message: `Could not find a module for type ${type}`,
data: { type },
});
}
return undefined; // eslint-disable-line no-undefined
}
pluginModule.__plugin_configuration = configuration;
return pluginModule;
}
type Component = any;
type ComponentsMap = { [key: string]: Component };
/**
* returns a navigation plugin based on its type. if not found, returns undefined
* @deprecated will be removed in next major version. Use NavigationUtils.resolveNavigationPlugin instead
* @param options to provide to the function
* @param options.category of navigation plugin to look for - can be either nav_bar or menu
* @param options.navigations navigations data to look for plugin type
* @param options.plugins map of available plugins
* @param options.defaultNavigationComponents map of default components to use (optional)
* @return plugin module found, if any
*/
export function getNavigationPlugin({
category,
navigations,
plugins,
defaultNavigationComponents = {},
}: {
category: "nav_bar" | "menu";
navigations: any[];
plugins: Plugin[];
defaultNavigationComponents: ComponentsMap;
}): any {
deprecationMessage(
"@applicaster/zapp-react-native-utils/PluginUtils.getNavigationPlugin",
"@applicaster/zapp-react-native-utils/NavigationUtils.resolveNavigationPlugin"
);
return (
findPluginByType(getNavigationType(category, navigations), plugins) ||
defaultNavigationComponents[toPascalCase(category)]
);
}
/**
* retrieves a Screen Plugin from the plugins array
* curried function `findScreenPlugin(type)(plugins)`
* @param type type of the plugin to look for.
* will be camelCased, and matched to the name property in the plugins
* @param plugins array of plugins to look into.
* @param plugins[].module React component for the plugin
* @param plugins[].name name of the plugin
* @param plugins[].type type of the plugin
* @return the plugin's module property (React component)
*/
export function findScreenPlugin(type) {
return function (plugins) {
return R.compose(
R.prop("module"),
R.find(R.propEq("name", toCamelCase(type)))
)(plugins);
};
}
/**
*
* @param manifestConfig - manifest.config of your plugin
* @param version - package.json of your plugin
*/
export function generateManifest({ manifestConfig, version }) {
const platform = platformSelect({
ios: "ios_for_quickbrick",
android: "android_for_quickbrick",
android_tv: "android_tv_for_quickbrick",
amazon: "amazon_fire_tv_for_quickbrick",
samsung_tv: "samsung_tv",
lg_tv: "lg_tv",
tvos: "tvos_for_quickbrick",
web: "samsung_tv",
});
return manifestConfig({ platform, version });
}
const getPluginType = R.pathOr("unknown_plugin_type", [
"state",
"screen",
"plugin_type",
]);
export const isPlayerPlugin = (routeState): boolean =>
getPluginType(routeState) === "player";