mattermost-redux
Version:
Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client
86 lines (85 loc) • 3.7 kB
JavaScript
;
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSelector = void 0;
exports.defaultMemoize = defaultMemoize;
exports.createSelectorCreator = createSelectorCreator;
exports.createStructuredSelector = createStructuredSelector;
/* eslint-disable */
function defaultEqualityCheck(a, b) {
return a === b;
}
function areArgumentsShallowlyEqual(equalityCheck, prev, next) {
if (prev === null || next === null || prev.length !== next.length) {
return false;
}
// Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
const length = prev.length;
for (let i = 0; i < length; i++) {
if (!equalityCheck(prev[i], next[i])) {
return false;
}
}
return true;
}
function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
let lastArgs = null;
let lastResult = null;
// we reference arguments instead of spreading them for performance reasons
return function () {
if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
// apply arguments instead of spreading for performance.
lastResult = func.apply(null, arguments);
}
lastArgs = arguments;
return lastResult;
};
}
function getDependencies(funcs) {
const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;
if (!dependencies.every((dep) => typeof dep === 'function')) {
const dependencyTypes = dependencies.map((dep) => typeof dep).join(', ');
throw new Error('Selector creators expect all input-selectors to be functions, ' +
`instead received the following types: [${dependencyTypes}]`);
}
return dependencies;
}
function createSelectorCreator(memoize, ...memoizeOptions) {
return (name, ...funcs) => {
const resultFunc = funcs.pop();
const dependencies = getDependencies(funcs);
const memoizedResultFunc = memoize(function () {
// apply arguments instead of spreading for performance.
return resultFunc?.apply(null, arguments);
}, ...memoizeOptions);
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
const selector = memoize(function () {
const params = [];
const length = dependencies.length;
for (let i = 0; i < length; i++) {
// apply arguments instead of spreading and mutate a local list of params for performance.
params.push(dependencies[i].apply(null, arguments));
}
// apply arguments instead of spreading for performance.
return memoizedResultFunc.apply(null, params);
});
selector.resultFunc = resultFunc;
selector.dependencies = dependencies;
return selector;
};
}
exports.createSelector = createSelectorCreator(defaultMemoize);
function createStructuredSelector(selectors, selectorCreator = exports.createSelector) {
if (typeof selectors !== 'object') {
throw new Error('createStructuredSelector expects first argument to be an object ' +
`where each property is a selector, instead received a ${typeof selectors}`);
}
const objectKeys = Object.keys(selectors);
return selectorCreator(objectKeys.map((key) => selectors[key]), (...values) => {
return values.reduce((composition, value, index) => {
composition[objectKeys[index]] = value;
return composition;
}, {});
});
}