@knighttower/utility
Version:
UtilityJs is a utility library that provides a collection of utility functions for various tasks. The library is designed to be easy to use and covers the most common use cases.
130 lines (118 loc) • 4.63 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
// [2023] [Knighttower] https://github.com/knighttower
/**
* @module proxyObject
* Convert to proxy to protect objects
* Allows to declare _private, _protected and _mutable - all arrays with prop names
* @example proxyObject({objectProps..., _protected: array(...)})
* @param {Object} object
* @return {Proxy}
* @usage const proxy = proxyObject({objectProps..., _protected: array(...), _private: array(...), _mutable: array(...)})
* @usage _protected: array(...) -> Cannot be modified
* @usage _private: array(...) -> Cannot be accessed
* @usage _mutable: array(...) -> Can be modified
*/
function proxyObject(object) {
// Initialize property access control sets
const _private = new Set(['_private', ...(object._private || [])]);
const _protected = new Set(['_protected', ..._private, ...(object._protected || [])]);
const _mutable = new Set(object._mutable || []);
const canMutate = (prop) => {
if (_protected.has(prop) && !_mutable.has(prop)) {
console.error(`Attempt to modify protected property: ${prop}`);
return false;
}
if (_private.has(prop) && !_mutable.has(prop)) {
console.error(`Attempt to modify private property: ${prop}`);
return false;
}
return true;
};
return new Proxy(object, {
get(target, prop, receiver) {
if (_private.has(prop)) {
console.error(`Attempt to access private property: ${prop}`);
return undefined;
}
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
if (!canMutate(prop)) {
return false;
}
return Reflect.set(target, prop, value, receiver);
},
deleteProperty(target, prop) {
if (!canMutate(prop)) {
return false;
}
return Reflect.deleteProperty(target, prop);
},
defineProperty(target, prop, descriptor) {
if (!canMutate(prop)) {
return false;
}
return Reflect.defineProperty(target, prop, descriptor);
},
ownKeys(target) {
return Reflect.ownKeys(target).filter((key) => !_private.has(key));
},
enumerate(target) {
const keys = Reflect.enumerate(target);
return keys.filter((key) => !_private.has(key));
},
has(target, prop) {
return !_private.has(prop) && Reflect.has(target, prop);
},
getOwnPropertyDescriptor(target, prop) {
if (_private.has(prop)) {
return undefined;
}
return Reflect.getOwnPropertyDescriptor(target, prop);
},
});
}
/**
* Enhances a class with proxy functionality to enforce access and mutation rules for its properties.
* This approach utilizes a higher-order function to wrap the class with a Proxy.
*/
/**
* Wraps a class with a Proxy to enforce private, protected, and mutable properties.
* @param {Function} BaseClass - The class to be wrapped.
* @returns {Proxy} A proxy-wrapped class enforcing the specified access controls.
* @usage
* // Example class to use with proxyClass
class MyClass {
constructor() {
this.publicProp = 'This can be accessed and modified.';
this.protectedProp = 'This cannot be modified.';
this.privateProp = 'This cannot be accessed or modified.';
this.mutableProp = 'This can be modified.';
this._protected = ['protectedProp'];
this._private = ['privateProp'];
this._mutable = ['mutableProp'];
}
}
// Enhanced class with proxyClass
const ProxyEnhancedMyClass = proxyClass(MyClass);
// Example usage
const instance = new ProxyEnhancedMyClass();
console.log(instance.publicProp); // Accessible
instance.publicProp = 'New value'; // Modifiable
console.log(instance.privateProp); // Attempt to access private property: privateProp
instance.mutableProp = 'Changed'; // Modifiable, even if protected
console.log(instance.mutableProp);
delete instance.privateProp;
*/
function proxyClass(BaseClass) {
return new Proxy(BaseClass, {
construct(target, args) {
const instance = new target(...args);
return proxyObject(instance);
},
});
}
exports.default = proxyObject;
exports.proxyClass = proxyClass;
exports.proxyObject = proxyObject;