0.5.1 • Published 2 years ago

proxy-tracker v0.5.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Proxy Tracker

Test Commit Number

Index

Purpose

This repository is born to give the chance to separate application logic from error checking and logging, as PragmaticProgrammer and CleanCode practices.

What bases ProxyTracker on and its power

It bases on Javascript Proxy. But for the classic Proxy, writing handler for trap function is uncomfortale.

with JS Proxy, the use of handler is heavy.

For example, if you want implements a trap for constructor (new class) and some traps for called functions into the istance, you should write this:

const callback_check_error = function(...args){/* body */}
const callback_spy1 = function(...args){/* body */}
const callbacl_logger = function(...args){/* body */}
const callback_spy2 = function(...args){/* body */}
const handler_apply = {apply(target, thisArg, body){
    callback_logger(...arguments);
    return target.apply(thisArg, args);
}}
const hanler_get = {get(target, prop, receiver){
    let value = Reflect.get(...arguments);
    if(isValueValidForProxy(value) return new Proxy(valye, handler_apply)
    else return value;
}}
const handler = {construct(target, args){
    callback_spy1(...args)
    callback_check_error(...args)
    callback_logger(...arguments)
    const instance = new target(...args)
    return new Proxy(instance, handler_get)
},
get(target, prop, receiver){
    callback_spy2(property);
    let value = Reflect.get(...arguments);
    if(isValueValidForProxy(value) return new Proxy(value, handler_apply)
    else return value;
}
}

With ProxyTracker

it's enougth to write this:

const handler = [{construct: [callback_spy1, callback_logger, callback_check_error], get: callback_spy2},

Stop. Only this.

Utilization

creation of Proxy

entity_to_track: Object | Class | Instance | Array | Function handler_track: Object Return: same type of entity_to_track, as workd Proxy handler_track has keys named in the traps list of Proxy, and each value is a function, an array of function and Object, or an Object recursively

const {ProxyTracker} = require('proxy-tracker')
const entity_tracked = new ProxyTracker(entity_to_track, handler_track)

example of logging and check error for a class

const checkErrorConstruct = function(target, [first_arg, second_arg]){assert(typeof fist_arg === 'number' && typeof second_arg === 'number')}
const checkErrorMethod = function(target, thisArg, args){if(target.name === 'sum') assert(typeof args[0] === 'number')}
const logger = console.log;
const entity_to_track = class {
    static staticMethod(arg){return arg}
    constructor(first, second){
        this.value = first + second // it's only ad example
    }
    sum(add){
        this.value += add
        return this.value
    }
}
const handler_track = {apply: logger, construct: [checkErrorConstruct, logger, {get: {apply: [checkErrorMethod, logger]}}]}

const entity_tracked = new ProxyTracker(entity_to_track, handler_track)

// example of use
new entity_tracked('string') // --> assert error
const instance = new entity_tracked(5,8) // --> console.log(entity_tracked, [5,8])
instance.sum('string') // --> assert error
instance.sum(4) // --> console.log([Function sum], thisArg, [4])

choose handler function

From 0.5.0v it is possible to choose the handler according to parameter name Warning: use it only on ProxyTracker. ProxyExtension must to be still tested.

const entity = {prop: {key: 'value', method(){/**/}, other_method(){}}};
const handler = {get: {FOR: 'method', apply: callback}}
const proxy = new ProxyTracker(entity, handler);

proxy.prop // -> it is not a proxy, because proxy is returned only if param is 'method'

proxy.method() // -> called callback
proxy.other_method() // -> callback is not called.

ProxyRemover

from 0.3.5 is possible to get the origin entity without proxy, also if is returned by trap. Both for ProxyTracker and ProxyExtension

eg of usage

const {ProxyTracker, ProxyRemover} = require('proxy-tracker')

class user_class{}
const handler = {construct: {get: {}}}
const user_class_proxy = new ProxyTracker(user_class) // --> return a Proxy. util.types.isProxy(user_class_proxy) === true
const instance_from_proxy = new user_class_proxy() // --> return a Proxy because there is a trap construct with next get trap
const origin_instance = ProxyRemover(instance_from_proxy) // return instance without proxy. util.types.isProxy(origin_instance) === false

DerivedClass

If you derive a proxy class, the traps has, get, set, construct are keeped. Only if you overwrite parameters or methods, the trap disappears. For the construct trap, it is keeped in the derived class. If you don't want traps to derived class, you must to do use ProxyRemover before deriving the class

ProxyExtension

from 0.4.0 is possible to use ProxyExtension, similary to ProxyTracker.

The arguments are the same for ProxyTracker, but the last callback is used for the returned value by trap. If handler permits the return of a proxy, and the value returned from callback is a function or object, then the trap returns a proxy.

example

const {ProxyExtension} = require('proxy-tracker')
const first_value = 'value'
const value_modified = 'value modified'
const callback_return_value_by_get_apply = function(t, thisarg, args){
            if(args[0]=first_value) return value_modified
            else return Reflect.apply(t, thisarg, args);}
const custom_function = function(st, sd, rd){/* body */}
const callback_log = function(...args){console.log(...args)}
const handler = {apply: [callback_log, callback_return_value_by_apply_trap]}
const proxy = ProxyExtension(custom_function, handler)

proxy(first_value /*, other arguments */) // -> console.log(arguments) and the function return value_modified
proxy(other_value /*, other arguments */) // -> console.log(arguments) and the function return custom_function(other_value /*, other arguments */)

handler

  • If handler or sub handler doesn't have any callback, then the value returned by trap is the real value.
  • If handler contains more callbacks, only the last callback is used for returning a value by trap.
  • If a trap has sub handler, the value returned by trap (real or by last callback) can be a proxy if the value is an Object or a Function.