@manuth/interceptor
Version:
Provides a convenient way to intercept method- property- and accessor-calls of an object.
175 lines • 5.6 kB
JavaScript
import cloneDeep from "lodash.clonedeep";
import { InterceptionCollection } from "./InterceptionCollection.js";
/**
* Provides the functionality to intercept methods of an object.
*
* @template T
* The type of the target of the {@linkcode Interceptor}.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export class Interceptor {
/**
* Initializes a new instance of the {@linkcode Interceptor} class.
*
* @param target
* The target of the interceptor.
*
* @param freeze
* A value indicating whether the interceptor should ignore future changes made to the {@linkcode target}.
*/
constructor(target, freeze) {
/**
* The interceptions.
*/
this.interceptions = new InterceptionCollection();
/**
* A value indicating whether the interceptor is disposed.
*/
this.disposed = false;
if (freeze) {
let clone = cloneDeep(target);
this.target = clone;
for (let property of Object.getOwnPropertyNames(target)) {
if (property in target) {
let descriptor = Object.getOwnPropertyDescriptor(target, property);
if (descriptor) {
Object.defineProperty(this.target, property, descriptor);
}
}
}
Object.assign(this.target, Object.assign({}, clone));
}
else {
this.target = target;
}
this.proxy = new Proxy(this.target, {
has: (target, property) => {
var _a, _b;
if (!this.Disposed) {
if (this.interceptions.has(property)) {
let properties = [
"Get",
"Set"
];
let interception = this.interceptions.get(property);
return (_b = (_a = interception === null || interception === void 0 ? void 0 : interception.Has) === null || _a === void 0 ? void 0 : _a.call(interception, target, property)) !== null && _b !== void 0 ? _b : properties.some((property) => interception === null || interception === void 0 ? void 0 : interception[property]);
}
else {
return property in target;
}
}
else {
return property in this.target;
}
},
get: (target, property) => {
var _a, _b;
if (!this.Disposed) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return (_b = (_a = this.interceptions.get(property)) === null || _a === void 0 ? void 0 : _a.Get(target, property)) !== null && _b !== void 0 ? _b : target[property];
}
else {
return this.target[property];
}
},
set: (target, property, value) => {
var _a;
if (!this.Disposed &&
this.interceptions.has(property)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(_a = this.interceptions.get(property)) === null || _a === void 0 ? void 0 : _a.Set(target, property, value);
}
else {
this.target[property] = value;
}
return true;
}
});
}
/**
* Gets the target of the interceptor.
*/
get Target() {
return this.target;
}
/**
* Gets the installed interceptions.
*/
get Interceptions() {
return new Map(this.interceptions);
}
/**
* Gets the proxy for intercepting calls.
*/
get Proxy() {
return this.proxy;
}
/**
* Gets a value indicating whether the interceptor is disposed.
*/
get Disposed() {
return this.disposed;
}
/**
* Adds a new property-interception.
*
* @template TKey
* The type of the specified {@linkcode key}.
*
* @param key
* The key of the interception to add.
*
* @param interception
* The interception to add.
*/
AddProperty(key, interception) {
if (!this.interceptions.has(key)) {
this.interceptions.set(key, interception);
}
else {
throw new RangeError(`An interception with the key \`${key.toString()}\` already exists!`);
}
}
/**
* Adds a new interception.
*
* @template TKey
* The type of the specified {@linkcode key}.
*
* @param key
* The key of the interception to add.
*
* @param interception
* The interception to add.
*/
AddMethod(key, interception) {
this.AddProperty(key, {
Get: (target, key) => {
return ((...args) => interception(target, target[key], ...args));
}
});
}
/**
* Deletes an interception.
*
* @param key
* The key of the interception to delete.
*/
Delete(key) {
this.interceptions.delete(key);
}
/**
* Clears all interceptions.
*/
Clear() {
this.interceptions.clear();
}
/**
* Disposes the interceptor.
*/
Dispose() {
this.disposed = true;
this.interceptions.clear();
}
}
//# sourceMappingURL=Interceptor.js.map