Socket
Socket
Sign inDemoInstall

fount

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fount - npm Package Compare versions

Comparing version 1.0.0-1 to 1.0.0-2

3

CHANGELOG.md

@@ -7,3 +7,6 @@ ## 1.x.x

* adds synchronous dependency resolution
* enables multi-level namespaces
* adds feature to get list of keys
* removes when as a dependency
* attempts to clean up some of the functions and eliminate repeated logic

@@ -10,0 +13,0 @@

8

package.json
{
"name": "fount",
"version": "1.0.0-1",
"version": "1.0.0-2",
"description": "A source from which dependencies flow",

@@ -27,4 +27,3 @@ "main": "./src/index.js",

"debug": "~2.1.3",
"lodash": "~3.7.0",
"when": "~3.7.2"
"lodash": "~3.7.0"
},

@@ -37,4 +36,5 @@ "devDependencies": {

"postal": "^1.0.2",
"sinon": "~1.14.1"
"sinon": "~1.14.1",
"when": "~3.7.2"
}
}

@@ -150,3 +150,13 @@ # Fount

## Resolving
## Synchronous vs. Asynchronous
Fount provides two sets of of functions for working with dependencies; one for when the dependencies are known to contain one or more promises and one for when the dependency chain is promise-free.
Each set consists of two functions; one for retrieving one or more dependencies directly and one for injecting dependencies into a function and calling it.
> **WARNING**: Fount cannot guarantee a synchronous return or dependency chain. Using the synchronous methods for a dependency that contains a promise will result in unexpected results.
## Asynchronous Methods
These methods return a promise that resolves once the dependency can be satisfied.
### Resolving
Resolving is pretty simple - fount will always return a promise to any request for a dependency.

@@ -170,27 +180,64 @@

You can also check in advance whether or not fount is able to resolve a dependency using `canResolve`:
### Injecting
Injecting is how you get fount to apply resolved dependencies to a function. It can be used the same way as AMD's define, with the arguments specified as strings, or, with the argument names parsed from the call itself.
```javascript
fount.canResolve( 'key1' );
// where 'a' and 'b' have been registered
fount.inject( [ 'a', 'b' ], function( a, b ) { ... } );
fount.canResolve( [ 'key1', 'key2' ] );
// within custom scope -- requires a and/or b to have been registered with 'scoped' lifecycle
fount.inject( [ 'a', 'b' ], function( a, b ) { ... }, 'myScope' );
// using keys across multiple containers
fount.inject( [ 'one.a', 'two.b' ], function( a, b ) { ... } );
// alternate support for multiple containers
fount.inject( function( one_a, two_b ) { ... } );
```
## Injecting
Injecting is how you get fount to invoke a function on your behalf with resolved dependencies. If you're familiar with AMD, it's somewhat similar to how define works.
## Synchronous Methods
These methods return a value immediately and assume that the dependencies involved do not contain promises. Remember: if a promise is encountered, it will result in unexpected results.
### Getting
As the name implies, `get` simply returns the value of the key from the container. It does still work like resolve in terms of plugging in dependency chains, but it does not resolve promises between dependency levels.
```javascript
let gimme = fount.get( 'gimme' ); // returns the value of gimme immediately
let scoped = fount.get( 'gimme', 'custom' ); // the value for scope 'custom'
// resolve multiple dependencies at once!
let { one, two } = fount.get( [ 'one', 'two' ] );
// resolve multiple dependencies ACROSS containers
let hash = fount.get( [ 'a.one', 'b.two' ] );
```
### Invoking
Invoking is how you get fount to apply dependencies to a function without promise resolution. It can be used the same way as AMD's define, with the arguments specified as strings, or, with the argument names parsed from the call itself.
Again: any promises encountered will result in odd behavior - write tests :)
```javascript
// where 'a' and 'b' have been registered
fount.inject( [ 'a', 'b' ], function( a, b ) { ... } );
fount.invoke( [ 'a', 'b' ], function( a, b ) { ... } );
// within custom scope -- requires a and/or b to have been registered with 'scoped' lifecycle
fount.inject( [ 'a', 'b' ], function( a, b ) { ... }, 'myScope' );
fount.invoke( [ 'a', 'b' ], function( a, b ) { ... }, 'myScope' );
// using keys across multiple containers
fount.inject( [ 'one.a', 'two.b' ], function( a, b ) { ... } );
fount.invoke( [ 'one.a', 'two.b' ], function( a, b ) { ... } );
// alternate support for multiple containers
fount.inject( function( one_a, two_b ) { ... } );
fount.invoke( function( one_a, two_b ) { ... } );
```
## Can Resolve
To check whether fount is able to resolve a dependency ahead of time, use `canResolve`:
```javascript
fount.canResolve( 'key1' );
fount.canResolve( [ 'key1', 'key2' ] );
```
## Configuration

@@ -233,2 +280,13 @@ Configuration of multiple containers, keys and values can be accomplished via a configuration hash passed to fount. The format of the hash is as follows:

## Key List
Fount will return an array of all keys registered:
```javascript
// top level includes all namespaces
fount.keys();
// limited by container
fount( "myContainer" ).keys();
```
## Purge

@@ -235,0 +293,0 @@ Fount provides three different ways to clean up:

@@ -1,13 +0,26 @@

var _ = require( 'lodash' );
var when = require( 'when' );
var whenFn = require( 'when/function' );
var whenKeys = require( 'when/keys' );
var debug = require( 'debug' )( 'fount' );
var util = require( 'util' );
var path = require( 'path' );
var fs = require( 'fs' );
var containers = {};
var parent;
var getDisplay = process.env.DEBUG ? displayDependency : _.noop;
const _ = require( 'lodash' );
const debug = require( 'debug' )( 'fount' );
const util = require( 'util' );
const path = require( 'path' );
const fs = require( 'fs' );
const getDisplay = process.env.DEBUG ? displayDependency : _.noop;
const DEFAULT = 'default';
let containers = {};
let parent;
function applyWhen( fn, args ) {
if( !args || args.length == 0 ) {
return Promise.resolve( fn() );
} else {
let promises = args.map( ( arg ) => {
return isPromisey( arg ) ? arg : Promise.resolve( arg );
} );
return Promise.all( promises )
.then( ( resolved ) => {
return fn.apply( null, resolved );
} );
}
}
function canResolve( containerName, dependencies, scopeName ) {

@@ -18,3 +31,3 @@ return getMissingDependencies( containerName, dependencies, scopeName ).length === 0;

function checkDependencies( fn, dependencies ) {
var fnString = fn.toString();
let fnString = fn.toString();
if ( /[(][^)]*[)]/.test( fnString ) ) {

@@ -32,4 +45,4 @@ return ( _.isFunction( fn ) && !dependencies.length ) ?

_.each( val, function( opt, key ) {
var dependency = opt;
var lifecycle;
let dependency = opt;
let lifecycle;
if ( _.isObject( opt ) ) {

@@ -59,3 +72,3 @@ if ( opt.scoped ) {

function container( name ) {
return ( containers[ name ] = containers[ name ] || { scopes: {} } );
return ( containers[ name ] = containers[ name ] || { scopes: {}, keyList: [] } );
}

@@ -87,4 +100,39 @@

function get( containerName, key, scopeName ) {
scopeName = scopeName || DEFAULT;
let missingKeys = getMissingDependencies( containerName, key, scopeName );
if ( missingKeys.length > 0 ) {
throw new Error( util.format( 'Fount could not resolve the following dependencies: %s', missingKeys.join( ', ' ) ) );
}
if ( _.isArray( key ) ) {
let ctr = container( containerName );
return key.reduce( ( acc, k ) => {
acc[ k ] = getValue( containerName, k, scopeName );
return acc;
}, {} );
} else {
return getValue( containerName, key, scopeName );
}
}
function getArguments( containerName, dependencies, fn, scopeName ) {
dependencies = checkDependencies( fn, dependencies );
let missingKeys = getMissingDependencies( containerName, dependencies, scopeName );
if ( missingKeys.length > 0 ) {
throw new Error( util.format( 'Fount could not resolve the following dependencies: %s', missingKeys.join( ', ' ) ) );
}
return dependencies.map( function( key ) {
let parts = key.split( /[._]/ );
let ctrName = containerName;
if ( parts.length > 1 ) {
ctrName = getContainerName( containerName, parts );
key = getKey( parts );
}
return get( ctrName, key, scopeName );
} );
}
function getContainerName( name, parts ) {
var lead = parts.slice( 0, -1 );
let lead = parts.slice( 0, -1 );
if( name === "default" ) {

@@ -102,5 +150,5 @@ return lead.join( '.' );

function getLoadedModule( name ) {
var parent = findParent( module );
var regex = new RegExp( name );
var candidate = _.find( parent.children, function( child ) {
let parent = findParent( module );
let regex = new RegExp( name );
let candidate = _.find( parent.children, function( child ) {
return regex.test( child.id ) && _.contains( child.id.split( '/' ), name );

@@ -117,8 +165,8 @@ } );

function getModuleFromInstalls( name ) {
var parent = findParent( module );
var installPath = _.find( parent.paths, function( p ) {
var modPath = path.join( p, name );
let parent = findParent( module );
let installPath = _.find( parent.paths, function( p ) {
let modPath = path.join( p, name );
return fs.existsSync( modPath );
} );
var mod;
let mod;
if ( installPath ) {

@@ -136,6 +184,6 @@ mod = require( path.join( installPath, name ) );

function getMissingDependencies( containerName, dependencies, scopeName ) {
scopeName = scopeName || 'default';
containerName = containerName || 'default';
scopeName = scopeName || DEFAULT;
containerName = containerName || DEFAULT;
dependencies = _.isArray( dependencies ) ? dependencies : [ dependencies ];
return _.reduce( dependencies, function( acc, key ) {
return dependencies.reduce( function( acc, key ) {
if ( _.isArray( key ) ) {

@@ -152,5 +200,4 @@ key.forEach( function( k ) {

function pushMissingKey( containerName, key, acc ) {
var originalKey = key;
var parts = key.split( /[._]/ );
function getValue( containerName, key, scopeName ) {
let parts = key.split( /[._]/ );
if ( parts.length > 1 ) {

@@ -160,11 +207,22 @@ containerName = getContainerName( containerName, parts );

}
var hasKey = container( containerName )[ key ] != null;
if( !hasKey ) {
acc.push( originalKey );
return container( containerName )[ key ]( scopeName );
}
function invoke( containerName, dependencies, fn, scopeName ) {
scopeName = scopeName || DEFAULT;
if ( _.isFunction( dependencies ) ) {
scopeName = fn;
fn = dependencies;
dependencies = [];
}
return acc;
let args = getArguments( containerName, dependencies, fn, scopeName );
if( args.length == 0 ) {
return fn();
} else {
return fn.apply( null, args );
}
}
function inject( containerName, dependencies, fn, scopeName ) {
scopeName = scopeName || 'default';
scopeName = scopeName || DEFAULT;
if ( _.isFunction( dependencies ) ) {

@@ -175,19 +233,13 @@ scopeName = fn;

}
dependencies = checkDependencies( fn, dependencies );
let args = getArguments( containerName, dependencies, fn, scopeName );
return applyWhen( fn, args );
}
var missingKeys = getMissingDependencies( containerName, dependencies, scopeName );
if ( missingKeys.length > 0 ) {
throw new Error( util.format( 'Fount could not resolve the following dependencies: %s', missingKeys.join( ', ' ) ) );
}
function isPromisey( x ) {
return x && x.then && typeof x.then == 'function'
}
var args = dependencies.map( function( key ) {
var parts = key.split( /[._]/ );
var ctrName = containerName;
if ( parts.length > 1 ) {
ctrName = getContainerName( containerName, parts );
key = getKey( parts );
}
return resolve( ctrName, key, scopeName );
} );
return whenFn.apply( fn, args );
function listKeys( containerName ) {
let ctr = container( containerName );
return ctr.keyList;
}

@@ -210,2 +262,16 @@

function pushMissingKey( containerName, key, acc ) {
let originalKey = key;
let parts = key.split( /[._]/ );
if ( parts.length > 1 ) {
containerName = getContainerName( containerName, parts );
key = getKey( parts );
}
let hasKey = container( containerName )[ key ] != null;
if( !hasKey ) {
acc.push( originalKey );
}
return acc;
}
function register() {

@@ -232,10 +298,16 @@ var args = getArgs( arguments );

key, containerName, lifecycle, getDisplay( fn ) );
var promise = wrappers[ lifecycle ]( containerName, key, fn, dependencies );
container( containerName )[ key ] = promise;
let value = wrappers[ lifecycle ]( containerName, key, fn, dependencies );
let ctr = container( containerName );
ctr[ key ] = value;
ctr.keyList.push( key );
if( containerName !== "default" ) {
container( "default" ).keyList.push( [ containerName, key ].join( "." ) );
}
container( containerName )[ key ] = value;
}
function registerModule( containerName, name ) {
var mod = getLoadedModule( name ) || getModuleFromInstalls( name );
let mod = getLoadedModule( name ) || getModuleFromInstalls( name );
if ( mod ) {
var lifecycle = _.isFunction( mod ) ? 'factory' : 'static';
let lifecycle = _.isFunction( mod ) ? 'factory' : 'static';
register( containerName, name, mod, lifecycle );

@@ -253,30 +325,28 @@ } else {

function resolve( containerName, key, scopeName ) {
scopeName = scopeName || 'default';
var missingKeys = getMissingDependencies( containerName, key, scopeName );
if ( missingKeys.length > 0 ) {
throw new Error( util.format( 'Fount could not resolve the following dependencies: %s', missingKeys.join( ', ' ) ) );
}
if ( _.isArray( key ) ) {
var hash = {};
var ctr = container( containerName );
key.forEach( function( k ) {
hash[ k ] = resolveKey( containerName, k, scopeName );
} );
return whenKeys.all( hash );
let value = get( containerName, key, scopeName );
if( _.isArray( key ) ) {
return whenKeys( value );
} else {
return resolveKey( containerName, key, scopeName );
return isPromisey( value ) ? value : Promise.resolve( value );
}
}
function resolveKey( containerName, key, scopeName ) {
var parts = key.split( /[._]/ );
if ( parts.length > 1 ) {
containerName = getContainerName( containerName, parts );
key = getKey( parts );
function resolveFunction( containerName, key, value, dependencies, store, scopeName ) {
let hasPromises = false;
let args = dependencies.map( function( dependencyKey ) {
let dependencyValue = getValue( containerName, dependencyKey, scopeName );
if( isPromisey( dependencyValue ) ) {
hasPromises = true;
}
return dependencyValue;
} );
if( hasPromises ) {
return applyWhen( value, args ).then( store );
} else {
return store( value.apply( null, args ) );
}
return container( containerName )[ key ]( scopeName );
}
function scope( containerName, name ) {
var ctr = container( containerName );
let ctr = container( containerName );
return ( ctr.scopes[ name ] = ctr.scopes[ name ] || {} );

@@ -300,109 +370,122 @@ }

var wrappers = {
factory: function( containerName, key, value, dependencies ) {
return function( scopeName ) {
if ( _.isFunction( value ) ) {
var dependencyContainer = containerName;
if ( value.__npm ) {
dependencyContainer = key;
}
if ( dependencies && canResolve( dependencyContainer, dependencies, scopeName ) ) {
var args = dependencies.map( function( key ) {
return resolve( dependencyContainer, key, scopeName );
} );
return whenFn.apply( value, args );
}
function whenKeys( hash ) {
let acc = {};
let promises = _.map( hash, ( promise, key ) => {
if( !isPromisey( promise ) ) {
promise = Promise.resolve( promise );
}
return promise.then( ( value ) => acc[ key ] = value );
} );
return Promise.all( promises )
.then( () => acc );
}
function factoryResolver( containerName, key, value, dependencies ) {
return function( scopeName ) {
if ( _.isFunction( value ) ) {
let dependencyContainer = containerName;
if ( value.__npm ) {
dependencyContainer = key;
}
return when.promise( function( resolve ) {
resolve( value );
} );
};
},
scoped: function( containerName, key, value, dependencies ) {
return function( scopeName ) {
var cache = scope( containerName, scopeName );
var store = function( resolvedTo ) {
cache[ key ] = _.cloneDeep( resolvedTo );
return resolvedTo;
};
if ( cache[ key ] ) {
return when.resolve( cache[ key ] );
} else if ( _.isFunction( value ) ) {
if( dependencies && canResolve( containerName, dependencies, scopeName ) ) {
var args = dependencies.map( function( key ) {
return resolve( containerName, key, scopeName );
} );
return whenFn.apply( value, args ).then( store );
if ( dependencies && canResolve( dependencyContainer, dependencies, scopeName ) ) {
let promises = false;
let args = dependencies.map( function( key ) {
let val = getValue( dependencyContainer, key, scopeName );
if( isPromisey( val ) ) {
promises = true;
}
return val;
} );
if( promises ) {
return applyWhen( value, args );
} else {
var resolvedValue;
return function() {
if( resolvedValue ) {
return when( resolvedValue );
} else {
return when.promise( function( res ) {
if( dependencies && canResolve( containerName, dependencies ) ) {
var args = dependencies.map( function( key ) {
return resolve( containerName, key, scopeName );
} );
res( whenFn.apply( value, args ).then( store ) );
} else {
res( value );
}
} );
}
};
return value.apply( null, args );
}
} else {
return when.promise( function( resolve ) {
if ( when.isPromiseLike( value ) ) {
value.then( store );
} else {
store( value );
}
resolve( value );
} );
}
}
return value;
};
}
function scopedResolver( containerName, key, value, dependencies ) {
return function( scopeName ) {
let cache = scope( containerName, scopeName );
let store = function( resolvedTo ) {
cache[ key ] = _.cloneDeep( resolvedTo );
return resolvedTo;
};
},
static: function( containerName, key, value, dependencies ) {
var promise;
if ( _.isFunction( value ) ) {
if( dependencies && canResolve( containerName, dependencies ) ) {
var args = dependencies.map( function( key ) {
return resolve( containerName, key );
} );
promise = whenFn.apply( value, args );
if ( cache[ key ] ) {
return cache[ key ];
} else if ( _.isFunction( value ) ) {
if( dependencies && canResolve( containerName, dependencies, scopeName ) ) {
return resolveFunction( containerName, key, value, dependencies, store, scopeName )
} else {
var resolvedValue;
return function() {
if( resolvedValue ) {
return when( resolvedValue );
} else {
return when.promise( function( res ) {
if( dependencies && canResolve( containerName, dependencies ) ) {
var args = dependencies.map( function( key ) {
return resolve( containerName, key );
} );
whenFn.apply( value, args )
.then( function( x ) {
resolvedValue = x;
res( x );
} );
} else {
res( value );
}
} );
if( dependencies && canResolve( containerName, dependencies, scopeName ) ) {
return resolveFunction( containerName, key, value, dependencies, store, scopeName )
}
};
}
}
} else {
promise = ( value && value.then ) ? value : when( value );
if ( isPromisey( value ) ) {
value.then( store );
} else {
store( value );
}
return value;
}
return function() {
return promise;
};
};
}
function staticResolver( containerName, key, value, dependencies ) {
let store = function( resolvedTo ) {
return resolvedTo;
};
if ( _.isFunction( value ) && !( value.toString() == "stub" && value.name == "proxy" ) ) {
if( !dependencies || dependencies.length == 0 ) {
return function() {
return value();
}
} else if( dependencies && canResolve( containerName, dependencies ) ) {
let val = resolveFunction( containerName, key, value, dependencies, store );
return function() {
return val;
}
} else {
let resolvedValue;
return function() {
if( resolvedValue ) {
return resolvedValue;
} else {
return new Promise( function( res ) {
if( dependencies && canResolve( containerName, dependencies ) ) {
let resolved = resolveFunction( containerName, key, value, dependencies, store );
if( isPromisey( resolved ) ) {
resolved.then( ( r ) => {
resolvedValue = r;
res( r );
} );
} else {
resolvedValue = resolved;
res( resolved );
}
} else {
res( value );
}
} );
}
};
}
} else {
return function() { return value; };
}
};
}
var fount = function( containerName ) {
const wrappers = {
factory: factoryResolver,
scoped: scopedResolver,
static: staticResolver
}
const fount = function( containerName ) {
if ( _.isObject( containerName ) ) {

@@ -413,3 +496,6 @@ configure( containerName );

canResolve: canResolve.bind( undefined, containerName ),
get: get.bind( undefined, containerName ),
invoke: invoke.bind( undefined, containerName ),
inject: inject.bind( undefined, containerName ),
keys: listKeys.bind( undefined, containerName ),
register: register.bind( undefined, containerName ),

@@ -425,11 +511,14 @@ registerModule: registerModule.bind( undefined, containerName ),

fount.canResolve = canResolve.bind( undefined, 'default' );
fount.inject = inject.bind( undefined, 'default' );
fount.register = register.bind( undefined, 'default' );
fount.registerModule = registerModule.bind( undefined, 'default' );
fount.registerAsValue = registerAsValue.bind( undefined, 'default' );
fount.resolve = resolve.bind( undefined, 'default' );
fount.canResolve = canResolve.bind( undefined, DEFAULT );
fount.get = get.bind( undefined, DEFAULT );
fount.invoke = invoke.bind( undefined, DEFAULT );
fount.inject = inject.bind( undefined, DEFAULT );
fount.keys = listKeys.bind( undefined, DEFAULT );
fount.register = register.bind( undefined, DEFAULT );
fount.registerModule = registerModule.bind( undefined, DEFAULT );
fount.registerAsValue = registerAsValue.bind( undefined, DEFAULT );
fount.resolve = resolve.bind( undefined, DEFAULT );
fount.purge = purge.bind( undefined );
fount.purgeAll = purgeAll;
fount.purgeScope = purgeScope.bind( undefined, 'default' );
fount.purgeScope = purgeScope.bind( undefined, DEFAULT );
fount.setModule = setModule;

@@ -436,0 +525,0 @@

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