golden-path
Version:
102 lines (73 loc) • 2.81 kB
JavaScript
import { assocPath, path as rPath, curry } from 'ramda';
const shallowEqual = require('shallowequal');
import resolvePath from './resolvePath';
import { TOKEN_HASH } from './constants';
const pathResolverCache = new Map();
const cachedResolvePath = (unResolvedPath, object) => {
const isPathResolutionCached = pathResolverCache.has(unResolvedPath);
if (isPathResolutionCached) {
return pathResolverCache.get(unResolvedPath);
}
let resolved;
try {
resolved = resolvePath(unResolvedPath, object);
} catch (err) {
throw new Error(`Golden Path :: Error while resolving the path "${unResolvedPath}" - Please check the Golden Path Syntax`);
}
const { isCacheablePath, ...resolvedPathConfig } = resolved;
if (isCacheablePath) {
pathResolverCache.set(unResolvedPath, resolvedPathConfig);
}
return resolvedPathConfig;
};
const update = curry((unResolvedPath, value, object) => {
let { path, paths, notExist } = cachedResolvePath(unResolvedPath, object);
if (notExist) { return object; }
if (path && !paths) { paths = [path]; }
let objectResult = object;
let newVal = value;
if (paths) {
paths.forEach((p) => {
if (typeof value === 'function') {
newVal = value(
rPath(p, object)
);
}
const isSameValue = shallowEqual(rPath(p, objectResult), newVal);
if (isSameValue) { return; }
objectResult = assocPath(p, newVal, objectResult)
});
}
return objectResult;
});
const weakMap = new WeakMap();
const EMPTY_ARRAY = [];
Object.freeze(EMPTY_ARRAY);
const get = curry((unResolvedPath, object) => {
const objectsWeakMap = weakMap.get(object);
if (objectsWeakMap) {
const isValueCached = objectsWeakMap.has(unResolvedPath);
if (isValueCached) {
return objectsWeakMap.get(unResolvedPath);
}
}
const value = (() => {
let { path, paths, notExist, isGreedy } = cachedResolvePath(unResolvedPath, object);
if (notExist) { return isGreedy ? EMPTY_ARRAY : undefined; }
if (path) { return rPath(path, object); }
if (paths) { return paths.map((p) => rPath(p, object)); }
})();
if (!objectsWeakMap) {
if (typeof object === 'object' && !!object) {
const map = new Map();
map.set(unResolvedPath, value);
weakMap.set(object, map);
}
} else {
objectsWeakMap.set(unResolvedPath, value);
}
return value;
});
const v = (value) => `${TOKEN_HASH}${value}${TOKEN_HASH}`;
const clearPathResolverCache = () => pathResolverCache.clear();
export { get, update, v, TOKEN_HASH, clearPathResolverCache };