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

nesting-doll

v1.0.3

Published

Nested context library using CLS

Downloads

9

Readme

Nesting Doll travis npm

This library is a simple component for building nested contexts/scopes (leveraging continuation-local-storage) which can be used for things such as a transaction logger. In fact, I built this expressly as the foundation for a nested transaction logger.

It exposes dolls which are containers for the current level context. Each doll maintains a "state" specific to that container. Each nested doll created tracks the outer most doll and the previous doll, allowing access to the top transaction and the previous transaction as you go down.

Install

npm install nesting-doll

API

var NestingDoll = require('nesting-doll');
var nestingDoll = NestingDoll.getDoll();

// or

var nestingDoll = new NestingDoll();

nestingDoll.nest(name, [state])

Creates new doll with given name and pre-populated with the data given as the dolls state.

var doll = nestingDoll.nest('foo', {timestamp: Date.now()});

nestingDoll.currentDoll()

Returns the current active doll.

nestingDoll.nest('foo').run(function () {
  var doll = nestingDoll.currentDoll();
  doll.set('test', 'value');
  asyncFunction('foo', fooCallback);
});

function fooCallback(err, value) {
  var doll = nestingDoll.currentDoll();

  console.log(doll.name);        // => 'foo'
  console.log(doll.get('test')); // => 'value'

  nestingDoll.nest('bar').run(function () {
    var doll = nestingDoll.currentDoll();
    doll.set('pizza', 'Is good!');
    asyncFunction('bar', barCallback);
  });
}

function barCallback(err, value) {
  var doll = nestingDoll.currentDoll();

  console.log(doll.name);                   // => 'bar'
  console.log(doll.get('test'));            // => undefined
  console.log(doll.get('pizza'));           // => 'Is good!'
  console.log(doll.previous().get('test')); // => 'value'
}

new Doll(name, namespace, [state])

Doll is an internal class and should not really be used on its own, but does house most of the functionality. Namespace is a CLS namespace.

var doll = nestingDoll.nest(name);

// is the same as

var doll = new Doll(name, namespace);

doll.run(function)

Run is an easy way to directly create a new doll context. Any function inside will have access to it.

var doll = nestingDoll.nest('foo');

doll.run(function () {
  // doll context is available here, and any functions inside of this callstack
  // will have access to this doll as well by calling nestingDoll.currentDoll()
});

doll.bind(function, [context])

Bind allows you to wrap a function that automatically creates a context when called. You can optionally pass in a CLS namespace context, which attaches the doll to that context.

var doll = nestingDoll.nest('foo');
var boundAsyncFn = doll.bind(asyncFn);

boundAsyncFn('foo', function (err, value) {
  // you have access to the doll context and other things similarly to doll.run
});

doll.rawBind(function, [context])

Raw bind is similar to doll.bind() above but does not run the doll nesting functionality (which sets outer and previous dolls). This allows binding multiple functions to the same doll context without running the nesting code more than once.

function createTransaction(name, transaction, callback) {
  var doll = nestingDoll.nest(name);

  // Creates CLS context
  var context = doll.namespace.createContext();

  var endTransaction = doll.rawBind(function () {
    doll.deactivate();

    var time = doll.get('timestamp');
    doll.set('diff', Date.now() - time);

    callback.apply(null, arguments);
  }, context);

  var startTransaction = doll.bind(function () {
    doll.activate();

    doll.set('timestamp', Date.now());
    transaction(endTransaction);
  }, context);

  startTransaction();
}

function asyncFn(key, callback) {
  // create nested transaction
  createTransaction(
    'db.find',
    function (end) {
      var currentDoll = nestingDoll.currentDoll();
      var previousDoll = currentDoll.previous();

      console.log(currentDoll.name);  // => 'db.find'
      console.log(previousDoll.name); // => 'asyncFn'

      db.find(key, end);
    },
    callback
  );
}

createTransaction(
  'asyncFn',
  function (end) {
    asyncFn('key', end);
  },
  function (err, value) {
    // your transaction is finished

    var currentDoll = nestingDoll.currentDoll();
    var previousDoll = currentDoll.previous();

    console.log(currentDoll.name); // => 'asyncFn'
    console.log(previousDoll);     // => 'null'
  }
);

// The above code runs asyncFn which itself runs db.find, which are both nested dolls
// and can be managed or read separately.

doll.previous() or doll.outer()

Returns the previous or outer most doll relative to this current doll. See examples above for usage.

doll.activate() or doll.deactivate()

This activates or deactivates a doll. Dolls are not active by default. Until you activate the doll you won't be able to nest any other dolls inside of it.

This is useful for explicitly ending a doll-based transaction, so subsequent dolls that aren't nested but called in the same scope do not polute your nested scope.

Credits

This library is born from the CLS module which othiym23 created. All of the magic comes CLS, while allowing this to stay simple and straight forward.

License

MIT