typedots
Version:
A simple way to get and set object properties using paths (aka dot notation) with TypeScript support
79 lines (72 loc) • 2.73 kB
JavaScript
const pathSplitRegexp = /(?<!\(.*)\.|(?<=.*\))\./g;
const parMatchRegexp = /[()]/g;
const get = (object, path) => path
.split(pathSplitRegexp).reduce((parent, current) => parent?.[current.replace(parMatchRegexp, '')], object);
const helpers$1 = {
getSubpaths: (object, path) => {
const [current, ...nested] = path.split(pathSplitRegexp)
.map((subpath) => subpath.replace(parMatchRegexp, ''));
return { current, nested };
},
updateDeep: (parent, path, rest, value, force = false) => {
const nestedProp = rest.shift();
const hasPathProperty = Object.prototype.hasOwnProperty.call(parent, path);
const hasPathObject = hasPathProperty && typeof parent[path] === 'object';
const hasPathObjectSubPath = hasPathObject
&& Object.prototype.hasOwnProperty.call(parent[path], nestedProp);
if (!nestedProp && (hasPathProperty || force)) {
parent[path] = value;
return true;
}
if (!nestedProp)
return false;
if (!rest.length) {
if (hasPathObjectSubPath) {
parent[path] = { ...parent[path], [nestedProp]: value };
return true;
}
if (!hasPathObjectSubPath && force) {
parent[path] = { [nestedProp]: value };
return true;
}
return false;
}
if (!hasPathObject && force) {
parent[path] = {};
}
return helpers$1.updateDeep(parent[path], nestedProp, rest, value, force);
},
};
const set = (object, path, value, force) => {
const { current, nested } = helpers$1.getSubpaths(object, path);
return helpers$1.updateDeep(object, current, nested, value, force);
};
const helpers = {
analyzeSubpath: (currentScope, subpath) => {
const parsedSubpath = subpath.replace(parMatchRegexp, '');
const isScopeObject = currentScope.value && typeof currentScope.value === 'object';
const hasNotSubpath = !isScopeObject
|| !Object.prototype.hasOwnProperty.call(currentScope.value, parsedSubpath);
if (hasNotSubpath)
return true;
currentScope.value = currentScope.value[parsedSubpath];
return false;
},
};
const has = (object, path) => {
const currentScope = { value: object };
return !path
.split(pathSplitRegexp)
.some((subpath) => helpers.analyzeSubpath(currentScope, subpath));
};
class Typedots {
get = (object, path) => get(object, path);
set = set;
has = (object, path) => has(object, path);
}
class BaseTypedots {
get;
set;
has;
}
export { BaseTypedots, Typedots as default, get, has, set };