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 🙏

© 2025 – Pkg Stats / Ryan Hefner

annoteJS

v0.1.5

Published

An annotation support framework for Javascript

Downloads

8

Readme

AnnoteJS Framework - annotations support framework

Git - github

Table of Contents

Installation

npm install annoteJS This installs in your projects location the promised-io module

Writing your own annotations

There are two types of annotation types supported:

  1. Decorator means that this type of annotation proxies the request through the annotation function and afterwards based on the annotation's implementation it calls or not the original function.
  2. NonDecorator means that the annotation is called first before instantiating the annotated class so it can decide what it should do with the specified class. In general we use this type of annotations if we don't intend to later use the annotated modules as standalone. For example a routing annotation does this. After you have written down your annotation always keep in mind to do the following and this is very strict:
    module.exports = {
        isDecorator: false,
        implementation: Standalone
    }

The above module.exports is standard for your written annotations and should contain the following info:

  • isDecorator - having true/false value - specifies if it should be a proxy and injected around the code or is a standalone that runs before the annotated module itself.
  • implementation - the value of this is the actual implementation of the annotation - it should not be a class for that it is called as a function

Example of annotations

In this section the two types of annotations supported are presented with some particularities and an implementation example. You can also find this implementations in the packages default annotations.

NonDecorator annotation

The following code shows how to write your own annotation of type NonDecorator. The NonDecorator annotation supports figuring out if your annotation is above a class or above a method so you are able to know if you have to instantiate the class or just use the method. For NonDecorator annotations this object is the annotation's implementation this In the implementation method you will receive an object with the following properties:

  • what - the annotation implementation in string format
  • type - method|class depending on the case. Keep in mind that class applies also for standalone functions - as stated in the below code
  • name - the name of the class/method/function
  • file - the file of the annotated module's implementation
  • originalFile - the original file on this of the annotated module's implementation
  • parentClass - [optional] - this field is received only on class methods in order to be able to instantiate the main class before running the method name
    function Standalone(clazz) {
        if(this.type == 'class') {
            try {
                _treatClass.call(this, clazz);
            } catch (ex) {
                throw ex;
            }
        } else {
            try {
                _treatMethod.call(this, clazz);
            } catch (ex) {
                throw ex;
            }
        }
    }
    
    function _treatClass(clazz) {
        var isClass = false;
        for(var element in clazz[this.name].prototype) {
            if(element != 'constructor' && element != '__proto__') {
                isClass = true;
                break;
            }
        }
    
        //if it is class instantiate it and put info on it
        if(isClass) {
            return;
        }
    
        clazz[this.name](1,2);
    }
    
    function _treatMethod(clazz) {
        var instance;
    
        console.log("Trying");
        if(clazz[this.parentClass]) {
            instance = new clazz[this.parentClass]();
        } else {
            return;
        }
    
        instance[this.name]();
    }
    
    module.exports = {
        isDecorator: false,
        implementation: Standalone
    }

Decorator Annotations

The following code shows how to write your own annotation of type Decorator. The Decorator annotation can be used over a class or over a method. What happens is that your annotation implementation will get injected inside the function and get executed first so you can then trigger the actual implementation's call before your operations or after or anyway around, being also able to change the return of the function. I don't recommend changing the return of the function for that can get very misleading. For Decorator annotations this object is the classe's/function's/method's this In the implementation method you will receive the same arguments as the original function. Also you will have a fn variable available in your annotation's implementation so you can later call the original function. Another important part is that you have a Promise variable also declared inside your original function and available in your annotation's implementation. The original function will change it's return type to a promise see the Usage Example section for more info

    function implementation(x, y) {
        var Promise = require('promised-io/promise');
        var self = this;
        return Promise.seq([
            function() {
                console.log("doing something before");
            },
            fn.bind(self, x, y),
            function(result) {
                console.log("doing something after");
                return result;
            }
        ]);
    }
    
    
    module.exports = {
        isDecorator: true,
        implementation: implementation
    }

Using the annotations

Naming

After you have written your possible annotations you must give the js files containing the implementation a suitable name for that the name of the file will be the annotation's name. Avoid naming annotations the same for that the last implementation will be the correct one. Example: /x/y/myAnnotations/My.js will be used inside modules like @My()

Registering

To register an annotation before you use the module you must run the following code:

    var annoteModule = require('annoteJS');
    annoteModule.registerAnnotations('/x/y/z/myAnnotations');

The registerAnnotations method receives absolute path of the folder location where you have your annotations declared.

Writing an annotated module

An annotated module module is a standard module that contains annotations and has 2 restrictions:

  1. module.exports must have the key name the same with the annotated function's name (in case of functions) or must have the key name the same with the class name
  2. You can have either a module with multiple functions or a module with just one class (for the moment this can't be combined)

Writing an annotated class module

    function AnnotatedClass() {}
    
    @My()
    AnnotatedClass.prototype.doSomething = function() {...}
    
    module.exports = {
        AnnotatedClass: AnnotatedClass
    }

Writing an annotated module with multiple functions but !!NO CLASS!!.

    @My()
    function annotatedF1() {}
    
    @My()
    function annotatedF2() {}
    
    module.exports = {
        annotatedF1: annotatedF1,
        annotatedF2: annotatedF2
    }

Using the annotated module

In order for the module to work you must require the annotatedModule as described in the bellow code. Annotation - My - path /x/y/annotations

    function My(x, y) {
        return Promise.seq([
            fn.bind(this, x, y),
            function(result) {
                console.log("the result is ", result);
                return result;
            }
        ]);
    }
    
    module.exports = {
        isDecorator: true,
        implementation: My
    }

Annotated Module - Calculator

    @My()
    function calculate(x, y) {
        return x + y;
    }
    
    module.exports = {
        calculate: calculate
    }

Usage of the annotated Module

    var annoteModule = require('annoteJS');
    annoteModule.registerAnnotations('/x/y/z/myAnnotations');
    
    var annoteJS = annoteModule.get(),
        annotatedCalculator = annoteJS.requireWithAnnotations('./path/to/my/Calculator.js');
    
    annotatedCalculator.calculate(2,3).then(function(result) {
        console.log("the official result of all in all module is ", result);
    }, function(err) {
        //something bad happened
    });

Annotation variables

You are also permitted to pass some variables to your annotations for example:

    function My() {
        console.log(My.path);
        console.log(My.stuff);
        console.log(My.defaultArgument);
    }
    @My(path=left,stuff=1)
    function annotatedFunction(){...}
    
    @My(critter)
    function defaultArgumentAnnotatedFunction() {...}
    
    module.exports = {
        annotatedFunction: annotatedFunction,
        defaultArgumentAnnotatedFunction: defaultArgumentAnnotatedFunction
    }

When no name for variable is passed the value inside the brackets is found on the defaultArgument field of the annotation's implementation.