New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

sack

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sack - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

HISTORY.md

185

lib/Container.js
var getArgs = require('typedef').getArguments;
var getName = require('typedef').getName;
var _ = require('underscore');

@@ -7,5 +8,5 @@

/**
* Basic dependency resolver that allows for the registering of types and
* factories via callback functions, as well as auto-guessing constructor
* injecting via parameter names
* Basic dependency resolver / IoC container that allows for the registering of
* types and factories via callback functions, as well as auto-guessing
* constructor injecting via parameter names.
* @constructor

@@ -16,4 +17,18 @@ */

this._types = {};
this.register('container', this);
}
this.register('resolver', this);
/**
* @param {Function=} T
* @param {Function=} closure
* @param {boolean=} shared
* @param {Object=} instance
*/
function Entry(T, closure, deps, shared, instance)
{
this.T = T || null;
this.closure = closure || null;
this.deps = deps || [];
this.shared = shared !== undefined ? shared : false;
this.instance = instance || null;
}

@@ -26,25 +41,60 @@

* @param {boolean=} shared If true, this dep will only be instantiated once (a
* la singleton)
* la singleton).
*/
Container.prototype.register = function(name, T, shared)
{
if (this._types[name])
throw new Error(
'Already registered dependency: "' + name + '"');
if (T instanceof Function)
return this.registerConstructor(name, T, shared);
else
return this.registerInstance(name, T, shared);
};
// Determine if there are any other deps in here
var deps = getArgs(T);
/**
* @param {String} name The name we want to register this dependency under.
* @param {Object} instance The object we want returned every time we resolve
* this dependency.
*/
Container.prototype.registerInstance = function(name, instance)
{
this._types[name] = new Entry(
null, null, null, true, instance);
};
this._types[name] = {
type: T,
deps: deps,
shared: !!shared,
instance: null
};
/**
* @param {String} name The name we want to register this dependency under.
* @param {Function} closure A callback function we want to call when creating
* this dependency.
* @param {boolean=} shared If true, this dependency will only be instantiated
* once (a la singleton).
*/
Container.prototype.registerClosure = function(name, closure, shared)
{
this._types[name] = new Entry(
null, closure, getArgs(closure), !!shared, null);
};
/**
* @param {Function} T
* @param {Function} factory
*/
Container.prototype.registerFactory = function(T, factory)
{
this._types['$$factory_function$$' + getName(T)] = new Entry(
T, factory, getArgs(factory), false, null);
};
/**
* @param {String} name The name we want to register this dependency under.
* @param {boolean=} shared If true, this dependency will only be instantiated
* once (a la singleton).
*/
Container.prototype.registerConstructor = function(name, T, shared)
{
this._types[name] = new Entry(
T, null, getArgs(T), !!shared, null);
};
/**
* Register a singleton (instantiated-once) class constructor dependency into
* this resolver.
* @param {String} name The name we want register something under.
* this container.
* @param {Function} T The class constructor of the type we want to register.

@@ -58,12 +108,28 @@ */

/**
* @param {String} name Abstract name.
* @return {bool} True if a type is registered already.
* @param {Function} T Constructor function we want to find the factory for.
* @return {Object} The dependency.
*/
Container.prototype.isRegistered = function(name)
Container.prototype.factory = function(T)
{
return !!this._types[name];
for (var n in this._types) {
var entry = this._types[n];
if (entry.T !== T || !entry.closure) continue;
var deps = this._resolveDeps(entry.deps);
return entry.closure.call(null, deps);
}
return this.build(T);
};
/**
* Create an object while resolving any dependencies we have have
* @param {Function} T
* @return {Object} The dependency.
*/
Container.prototype.build = function(T)
{
var deps = this._resolveDeps(getArgs(T));
return callNew(T, deps);
};
/**
* @param {String} name The string tag of the dependency we want to create.

@@ -74,52 +140,49 @@ * @return {Object} The dependency.

{
var deps;
var _this = this;
// Use parameter names of the function to bring in more deps
if (name instanceof Function) {
var T = name;
deps = _(getArgs(T)).map(function(d) { return _this.make(d); });
return callNew(T, deps);
return this.factory(name);
} else if (!_(name).isString()) {
return name;
}
// Nop if we are passing in something weird
if (!_(name).isString())
return name;
var entry = this._resolve(name);
var info = this._resolve(name);
// Short circuit if we've already got our
if (entry.shared && entry.instance) {
return entry.instance;
}
// If we have just a normal thing, return it
if (!(info.type instanceof Function))
return info.type;
// Resolve all of the expressed dependencies
var deps = this._resolveDeps(entry.deps);
// Resolve all string deps into make deps
// Create
var instance;
if (!info.shared || !info.instance) {
deps = _(info.deps).map(function(d) { return _this.make(d); });
instance = callNew(info.type, deps);
// Stash singleton
if (info.shared)
info.instance = instance;
if (entry.T) {
instance = callNew(entry.T, deps);
} else {
instance = info.instance;
instance = entry.closure.call(null, deps);
}
// Stash singleton
if (entry.shared)
entry.instance = instance;
return instance;
};
// Give us a way to instantiate a new class with an array of args
function callNew(T, args)
/**
* Resolve a list of string dependencies into real dependencies
* @param {Array.<String>} deps
* @return {Array.<Object>}
* @private
*/
Container.prototype._resolveDeps = function(deps)
{
function F() { return T.apply(this, args); }
F.prototype = T.prototype;
return new F();
}
var _this = this;
return _(deps).map(function(d) { return _this.make(d); });
};
/**
* Resolve the name of a dep
* @param {String} name The dep name.
* @return {{type: Function, deps: Array.<String>}} Type T.
* Resolve information about a dependency.
* @param {String} name The dependency name.
* @return {Entry} Information about this named dependency.
* @private

@@ -136,1 +199,9 @@ */

// Give us a way to instantiate a new class with an array of args
function callNew(T, args)
{
function F() { return T.apply(this, args); }
F.prototype = T.prototype;
return new F();
}
{
"name": "sack",
"version": "1.0.0",
"version": "1.1.0",
"description": "Inversion-of-control container for all your dependency injection needs.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -19,3 +19,3 @@ # Sack

## Rationale
## Introduction

@@ -33,29 +33,47 @@ This is a simple *Inversion of Control Container*. It provides the mechanism

The functionality of Sack lies within its `Container` class.
Dependencies are all managed via a `Container` instance:
### Registering Objects
Register a dependency with a container with a stringly-typed tag and either a
constructor, instance, or closure.
```javascript
var Container = require('sack').Container;
...
var container = new Container();
```
// Create a new instance every request:
### Registering Objects
Register a class constructor that will get executed every time the dependency
is resolved, creating a new instance:
```javascript
container.register('service', MyService);
```
// Create a new instance on first request, then reuse (singleton-esque):
Register a constructor function that will get executed *one time* when the
first time a dependency is resolved, and then re-used after that (singleton):
```javascript
container.shared('service', MyService);
```
// Use an existing instance:
container.register('service', new Service());
Register an existing object instance as a dependency:
// Have a (lazily evaluated) callback provide the dependency every request
```javascript
container.register('service', someService);
```
Register a (lazily evaluated) callback to provide the dependency on every
request:
```javascript
container.register('service', function() {
return new MyService();
});
```
// Use a callback to provide the dependency, but only once (singleton):
Registered a callback to provide the dependency the first time it is requested,
and then re-use it all subsequent times (singleton via callback):
```javascript
container.shared('service', function() {

@@ -67,2 +85,12 @@ return new MyService();

Register a factory callback for a specific class constructor. This is useful
for allowing objects to create several of another object without explictly
knowing how:
```javascript
container.registerFactory(GameEntity, function(pool) {
return pool.aquire(GameEntity);
});
```
### Resolving Objects

@@ -69,0 +97,0 @@

var test = require('tape');
var Resolver = require('../lib/Container.js');
var Container = require('../lib/Container.js');

@@ -7,3 +7,3 @@ test('Basic single dep constructor registration', function(t) {

var r = new Resolver();
var r = new Container();
var x = 't';

@@ -17,20 +17,6 @@ var T = function T() {};

test('Register throws', function(t) {
t.plan(1);
var r = new Resolver();
var x = 't';
var T = function T() {};
r.register(x, T);
t.throws(function() {
r.register(x, T);
}, 'Dupe on register');
});
test('Resolve method throws', function(t) {
t.plan(1);
var r = new Resolver();
var r = new Container();

@@ -43,5 +29,5 @@ t.throws(function() {

test('Basic dep track', function(t) {
t.plan(5);
t.plan(5);
var r = new Resolver();
var r = new Container();
var A = function() { t.ok(true, 'A ctor fired'); };

@@ -66,3 +52,3 @@ var B = function() { t.ok(true, 'B ctor fired'); };

var r = new Resolver();
var r = new Container();
r.register('T', function(A, B, C) {});

@@ -78,3 +64,3 @@ t.throws(function() {

var r = new Resolver();
var r = new Container();
function T(a) {

@@ -93,3 +79,3 @@ t.strictEqual(true, a instanceof A, 'a passed in');

var r = new Resolver();
var r = new Container();
function T() { t.ok(true, 'T ctor fired'); }

@@ -105,3 +91,3 @@ r.shared('t', T);

var r = new Resolver();
var r = new Container();
function T(a) {

@@ -126,3 +112,3 @@ t.ok(true, 'T ctor called');

var r = new Resolver();
var r = new Container();
var weird = {};

@@ -137,3 +123,3 @@

var r = new Resolver();
var r = new Container();
var DEP = {};

@@ -167,3 +153,3 @@ var B_DEP = {};

var r = new Resolver();
var r = new Container();
r.register('a', thing);

@@ -174,1 +160,28 @@ t.strictEqual(thing, r.make('a'), 'making returns instance');

});
test('Self register', function(t) {
t.plan(2);
var c = new Container();
t.strictEqual(c.make('container'), c, 'got em');
t.strictEqual(c.make('container'), c, 'got em');
});
test('Factory style', function(t) {
t.plan(4);
function M() { }
var LOL = {};
var container = new Container();
container.registerFactory(M, function() {
t.pass('factory fired');
return LOL;
});
t.strictEqual(container.factory(M), LOL, 'made it'); // 2x
t.strictEqual(container.factory(M), LOL, 'made it'); // 2x
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc