UNPKG

@woocommerce/data

Version:
239 lines (238 loc) 7.4 kB
/** * External dependencies */ import { addQueryArgs } from '@wordpress/url'; /** * Internal dependencies */ import CRUD_ACTIONS from './crud-actions'; import { getResourceName } from '../utils'; /** * Get a REST path given a template path and URL params. * * @param templatePath Path with variable names. * @param query Item query. * @param parameters Array of items to replace in the templatePath. * @return string REST path. */ export const getRestPath = (templatePath, query, parameters) => { var _a; let path = templatePath; (_a = path.match(/{(.*?)}/g)) === null || _a === void 0 ? void 0 : _a.forEach((str, i) => { path = path.replace(str, parameters[i].toString()); }); const regex = new RegExp(/{|}/); if (regex.test(path.toString())) { throw new Error('Not all URL parameters were replaced'); } return addQueryArgs(path, query); }; /** * Get a key from an item ID and optional parent. * * @param query Item Query. * @param urlParameters Parameters used for URL. * @return string */ export const getKey = (query, urlParameters = []) => { const id = typeof query === 'string' || typeof query === 'number' ? query : query.id; if (!urlParameters.length) { return id; } return urlParameters.join('/') + '/' + id; }; /** * This function takes an array of items and reduces it into a single object, * where each key is a unique identifier generated by * combining the item ID and optional URL parameters. * It also returns an array of these keys (`ids`). * * @param {Array<Item>} items - The items to process. * @param {Array<IdType>} urlParameters - The URL parameters used to generate keys. * @param {Record<string, Item>} currentState - The current state data to merge with. * @return {organizeItemsByIdReturn} An object with two properties: `objItems` and `ids`. */ export const organizeItemsById = (items, urlParameters = [], currentState = {}) => { const ids = []; const objItems = {}; const hasUrlParams = urlParameters.length > 0; items.forEach((item) => { const key = hasUrlParams ? getKey(item.id, urlParameters) : item.id; ids.push(key); objItems[key] = { ...(currentState[key] || {}), ...item, }; }); return { objItems, ids }; }; /** * Filters the input data object, returning a new object that contains only the keys * specified in the keys array. * * @param {Record<string, unknown>} data - The original data object to filter. * @param {IdType[]} keys - An array of keys that should be included in the returned object. * @return {Record<string, unknown>} A new object containing only the specified keys. */ export function filterDataByKeys(data, keys) { return keys.reduce((acc, key) => { if (data[key]) { acc[key] = data[key]; } return acc; }, {}); } /** * Parse an ID query into a ID string. * * @param query Id Query * @return string ID. */ export const parseId = (query, urlParameters = []) => { if (typeof query === 'string' || typeof query === 'number') { return { id: query, key: query, }; } return { id: query.id, key: getKey(query, urlParameters), }; }; /** * Create a new function that adds in the namespace. * * @param fn Function to wrap. * @param namespace Namespace to pass to last argument of function. * @return Wrapped function */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export const applyNamespace = (fn, namespace, // eslint-disable-next-line @typescript-eslint/no-explicit-any defaultArgs = []) => { return (...args) => { defaultArgs.forEach((defaultArg, index) => { // skip first item, as that is the state. if (args[index + 1] === undefined) { args[index + 1] = defaultArg; } }); return fn(...args, namespace); }; }; /** * Get the key names from a namespace string. * * @param namespace Namespace to get keys from. * @return Array of keys. */ export const getNamespaceKeys = (namespace) => { var _a; const keys = []; (_a = namespace.match(/{(.*?)}/g)) === null || _a === void 0 ? void 0 : _a.forEach((match) => { const key = match.substr(1, match.length - 2); keys.push(key); }); return keys; }; /** * Get URL parameters from namespace and provided query. * * @param namespace Namespace string to replace params in. * @param query Query object with key values. * @return Array of URL parameter values. */ export const getUrlParameters = (namespace, query) => { if (typeof query !== 'object') { return []; } const params = []; const keys = getNamespaceKeys(namespace); keys.forEach((key) => { if (query.hasOwnProperty(key)) { params.push(query[key]); } }); return params; }; /** * Check to see if an argument is a valid type of ID query. * * @param arg Unknow argument to check. * @param namespace The namespace string * @return boolean */ export const isValidIdQuery = (arg, namespace) => { if (typeof arg === 'string' || typeof arg === 'number') { return true; } const validKeys = ['id', ...getNamespaceKeys(namespace)]; if (arg && typeof arg === 'object' && arg.hasOwnProperty('id') && JSON.stringify(validKeys.sort()) === JSON.stringify(Object.keys(arg).sort())) { return true; } return false; }; /** * Replace the initial argument with a key if it's a valid ID query. * * @param args Args to check. * @param namespace Namespace. * @return Sanitized arguments. */ export const maybeReplaceIdQuery = (args, namespace) => { const [firstArgument, ...rest] = args; if (!firstArgument || !isValidIdQuery(firstArgument, namespace)) { return args; } const urlParameters = getUrlParameters(namespace, firstArgument); const { key } = parseId(firstArgument, urlParameters); return [key, ...rest]; }; /** * Clean a query of all namespaced params. * * @param query Query to clean. * @param namespace * @return Cleaned query object. */ export const cleanQuery = (query, namespace) => { const cleaned = { ...query }; const keys = getNamespaceKeys(namespace); keys.forEach((key) => { delete cleaned[key]; }); return cleaned; }; /** * Get the identifier for a request provided its arguments. * * @param name Name of action or selector. * @param args Arguments for the request. * @return Key to identify the request. */ export const getRequestIdentifier = getResourceName; /** * Get a generic action name from a resource action name if one exists. * * @param action Action name to check. * @param resourceName Resurce name. * @return Generic action name if one exists, otherwise the passed action name. */ export const getGenericActionName = (action, resourceName) => { switch (action) { case `create${resourceName}`: return CRUD_ACTIONS.CREATE_ITEM; case `delete${resourceName}`: return CRUD_ACTIONS.DELETE_ITEM; case `update${resourceName}`: return CRUD_ACTIONS.UPDATE_ITEM; } return action; };