npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

oz-decorators

v0.0.4

Published

These decorators classes helps you focus on your logic and hides the issues regarding decorators

Downloads

14

Readme

OZ-Decorators

These decorators classes helps you focus on your logic and hides the issues regarding decorators.


With this module you can decorate classes, methods, members and accessors (properties with get and or set).

API

// Decorates the code (class, function) and returns afactory method to an instance of the specified DecoratorBase (any argument will be passed to the constructor)

// usage: @decorate(MergeClassesDecorator)(ConsoleLogger, ExtraLog)
export default function decorate(decoratorCtor: Constructor<BaseDecorator>)

// Shared decorator API (no need to implement, next classes are the real bases)
interface BaseDecorator {
  decorate(...args: any[]): any
}

// base for decorating classes
abstract class ClassDecorator {
  // Once decorated, this method is called with new class construtcor (cls parameter).
  // Here is where the class modification should take place
  protected abstract onCreated(cls: Constructor)
}

type DecoratingMethodHandler = (target: any, propertyKey: string, descriptor: PropertyDescriptor, ...args: any[]) => any

type WrapingMethodHandler = (key: string, invoker : Function, ...args: InputParameter[]) => void

// class to decorate a field member 
class MemberDecorator  {
  
  constructor(
    onDecoratingMethod: DecoratingMethodHandler, // called when decorated
    wrapingGetMethod: WrapingMethodHandler, // wrapping method for getting member value
    wrapingSetMethod?: WrapingMethodHandler // wrapping method for setting member value
    ) {...}
}

// class to decorate a accessor (property with get and or set)
class AccessorDecorator {
  
  constructor(
    onDecoratingMethod: DecoratingMethodHandler, // called when decorated
    wrapingGetMethod: WrapingMethodHandler, // wrapping method for getting member value
    wrapingSetMethod?: WrapingMethodHandler // wrapping method for setting member value
    ) {...}
}

// class to decorte methods (functions)
class MethodDecorator {
  constructor(
    onDecoratingMethod: DecoratingMethodHandler, // called when decorated
    wrapingMethod?: WrapingMethodHandler, // extends the calling of the decorated method
    ...args:any[]
  ) {...}
}

// class to decorte methods parameters (functions arguments)
class MethodParameterDecorator {

  // can be overriden
  /*virtual*/ onParamMetaData(
    paramName: string, 
    methodName: string,  
    index: number // parameter's index in the arguments list
  )
}

Usage

Add behavior to method

To wrap method with extra behavior you can use MethodDecorator This is how to add log on methods

function onDecorating(target: any, propertyKey: string, descriptor: PropertyDescriptor) : any {
}

function wrapingMethod(key: string, invoker : Function, ...args:InputParameter[]){
  console.log(`calling ${key} in wrapingMethod`)
  invoker()  
}

class Test {
  @decorate(MethodDecorator)(onDecorating, wrapingMethod)
  foo() {
    console.log('foo')
  }
}

Now let's call it

let t = new Test()
t.foo()

output will be

calling foo in wrapingMethod
foo

Add functionality to class

Here is how to add log functionality to Test class.

First, we'll declare a class that will have the logging functionality

class Logger {
  log(level: number, message: string) {
    console.log(`${level}: ${message}`)
  }

  logDebug(message: string) {
    this.log(0, message)
  }

  logWarn(message: string) {
    this.log(1, message)
  }

  logError(message: string) {
    this.log(2, message)
  }
}

For ease of use (and 'compile time' error), we'll merge types:

interface Test extends Logger {}

Now let's decorate Test class (merge it with Logger):

@decorate(ClassMixinDecorator)(Logger)
class Test {
  @decorate(MethodDecorator)(onDecorating, wrapingMethod)
  foo() {
    console.log('foo')
    this.logDebug('debugging foo')
  }
}

We'll get:

calling foo in wrapingMethod
foo
0: debugging foo

Dispatcher class

Here is how to use decorators and Dispatcher class to dispatch actions in run-time:

First we'll declare an Action class like so:

class Action {
  id: number

  inputParam1?: string
  inputParam2?: string
}

Now let's declare a dispatcher class that will call methods accordingly.

Two methods must be defined:

  1. getKey - this returns the key from the dispatched object
  2. getParamFromDispatched - this returns a value from the dispatched object to be injected to a parameter on the target method.
class ActionDispatcher extends Dispatcher<number, Action> {
  
  protected getKey(obj: Action): number {
    return obj.id
  }
  
  protected getParamFromDispatched(meta: InputParameter, obj: Action) {
    return obj[meta.name]
  }
}

Method will be "dispatchable" after decorating with @classDispacher().

Actual dispatched methods can be private.

@classDispacher()
class ActionDispatcher {

  ...

  @methodDispatcher(1)
  private action1() {
    console.log("in action1")
  }

  @methodDispatcher(2)
  private action2(@paramDispatcher() inputParam1: string) {
    console.log(`in action2: ${inputParam1}`)
  }

  @methodDispatcher()
  private defaultAction(@paramDispatcher() inputParam1: string,
    @paramDispatcher() inputParam2: string) {
    console.log(`in defaultAction: ${inputParam1}, ${inputParam2}`)
  }
}

Usage:

let ad = new ActionDispatcher()

ad.dispatch({ id:1 }) // action1 will be invoked

ad.dispatch({ id:2, inputParam1: 'value2' })  // action2 will be invoked with 'value2' injected to inputParam1 parameter

ad.dispatch({ id: 100, inputParam1: 'value101', inputParam2: 'value102' }) // defaultAction will be invoked

output:

in action1
in action2: value2
in defaultAction: value101, value102