victory-core
Version:
97 lines (88 loc) • 3.19 kB
JavaScript
import * as React from "react";
import { evaluateProp } from "./helpers";
/*
USER_PROPS_SAFELIST is to contain any string deemed safe for user props.
The startsWidth array will contain the start of any accepted user-prop that
starts with these characters.
The exactMatch will contain a list of exact prop names that are accepted.
*/
const USER_PROPS_SAFELIST = {
startsWith: ["data-", "aria-"],
exactMatch: []
};
// Normally we'd use Template Literal Types, but we're avoiding it to maximize TS compatibility with TS < 4.1
// `data-${string}` | `aria-${string}`;
/**
* doesPropStartWith: Function that takes a prop's key and runs it against all
* options in the USER_PROPS_SAFELIST and checks to see if it starts with any
* of those options.
* @param {string} key: prop key to be tested against whitelist
* @returns {Boolean}: returns true if the key starts with an option or false if
* otherwise
*/
const doesPropStartWith = key => {
let startsWith = false;
USER_PROPS_SAFELIST.startsWith.forEach(starterString => {
const regex = new RegExp(`\\b(${starterString})(\\w|-)+`, "g");
if (regex.test(key)) startsWith = true;
});
return startsWith;
};
/**
* isExactMatch: checks to see if the given key matches any of the 'exactMatch'
* items in the whitelist
* @param {String} key: prop key to be tested against the whitelist-exact match
* array.
* @returns {Boolean}: return true if whitelist contains that key, otherwise
* returns false.
*/
const isExactMatch = key => USER_PROPS_SAFELIST.exactMatch.includes(key);
/**
* testIfSafeProp: tests prop's key against both startsWith and exactMatch values
* @param {String} key: prop key to be tested against the whitelist
* @returns {Boolean}: returns true if found in whitelist, otherwise returns false
*/
const testIfSafeProp = key => {
if (doesPropStartWith(key) || isExactMatch(key)) return true;
return false;
};
/**
* Asserts that value is not null or undefined, throwing an error if it is.
* @param value The value to assert
* @param message The error message to throw
*/
export function assert(value, message) {
if (value === undefined || value === null) {
throw new Error(message);
}
}
/**
* getSafeUserProps - function that takes in a props object and removes any
* key-value entries that do not match filter strings in the USER_PROPS_SAFELIST
* object.
*
* @param {Object} props: props to be filtered against USER_PROPS_SAFELIST
* @returns {Object}: object containing remaining acceptable props
*/
export const getSafeUserProps = props => {
const propsToFilter = {
...props
};
return Object.fromEntries(Object.entries(propsToFilter).filter(_ref => {
let [key] = _ref;
return testIfSafeProp(key);
}).map(_ref2 => {
let [key, value] = _ref2;
return [key, evaluateProp(value, props)];
}));
};
/**
* Wraps a component and adds safe user props
*
* @param {ReactElement} component: parent component
* @param {Object} props: props to be filtered
* @returns {ReactElement} modified component
*/
export const withSafeUserProps = (component, props) => {
return /*#__PURE__*/React.cloneElement(component, getSafeUserProps(props));
};