Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

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 0.0.6 to 0.1.0

13

CHANGELOG.md

@@ -0,3 +1,14 @@

## 0.1.X
### 0.1.0
* #7 - Add better error reporting - include all unresolvable keys
* #6 - Export canResolve to allow consumers to check in advance
* Backfill dependencies from NPM modules when available
* Add support for bulk registration
## 0.0.X
### 0.0.6
* Fix bug where things like sinon.stub cause dependency check to throw an exception
* When a function's dependencies cannot be resolved, return the function rather than throw an exception
* When a function's dependencies cannot be resolved, return the function rather than throw an exception

31

gulpfile.js

@@ -1,15 +0,26 @@

var gulp = require( 'gulp' ),
mocha = require( 'gulp-mocha' );
var gulp = require( 'gulp' );
var bg = require( 'biggulp' )( gulp );
gulp.task( 'test', function() {
gulp.src( './spec/*.spec.js' )
.pipe( mocha( { reporter: 'spec' } ) )
.on( 'error', function( err ) { console.log( err.stack ); } );
gulp.task( 'coverage', bg.withCoverage() );
gulp.task( 'coverage-watch', function() {
bg.watch( [ 'coverage' ] );
} );
gulp.task( 'watch', function() {
gulp.watch( [ './src/**', './spec/**' ], [ 'test' ] );
gulp.task( 'show-coverage', bg.showCoverage() );
gulp.task( 'continuous-specs', function() {
return bg.test();
} );
gulp.task( 'default', [ 'test', 'watch' ], function() {
} );
gulp.task( 'specs-watch', function() {
bg.watch( [ 'continuous-specs' ] );
} );
gulp.task( 'test-and-exit', function() {
return bg.testOnce();
} );
gulp.task( 'default', [ 'coverage', 'coverage-watch' ], function() {} );
gulp.task( 'specs', [ 'continuous-specs', 'specs-watch' ], function() {} );
gulp.task( 'test', [ 'test-and-exit' ] );
{
"name": "fount",
"version": "0.0.6",
"version": "0.1.0",
"description": "A source from which dependencies flow",

@@ -26,12 +26,14 @@ "main": "./src/index.js",

"dependencies": {
"debug": "^1.0.4",
"lodash": "^2.4.1",
"when": "^3.3.1"
"debug": "~2.1.3",
"lodash": "~3.7.0",
"when": "~3.7.2"
},
"devDependencies": {
"gulp": "^3.8.6",
"gulp-mocha": "^0.5.1",
"should": "^4.0.4",
"sinon": "^1.12.1"
"biggulp": "~0.0.2",
"chai": "~2.1.1",
"chai-as-promised": "~4.3.0",
"gulp": "~3.8.11",
"postal": "^1.0.2",
"sinon": "~1.14.1"
}
}

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

## A note about style and safety
Fount supports two styles of identifying dependency: string array (like AMD) and by argument names (like Angular).
Fount supports two styles of identifying dependency: string array (like AMD) and by argument names (like Angular).

@@ -42,3 +42,3 @@ Example:

```javascript
fount( 'myContainer' ).resolve( 'myKey' ).then( function( value ) {
fount( 'myContainer' ).resolve( 'myKey' ).then( function( value ) {
// do something cool

@@ -48,3 +48,3 @@ } );

// same as above, but terser
fount.resolve( 'myContainer.myKey' ).then( function( value ) {
fount.resolve( 'myContainer.myKey' ).then( function( value ) {
// do something cool

@@ -73,3 +73,3 @@ } );

## Registering
## Registering
Registering is simple - provide a string name and then supply either a value, function or promise. See each section for more detail.

@@ -148,2 +148,10 @@

You can also check in advance whether or not fount is able to resolve a dependency using `canResolve`:
```javascript
fount.canResolve( 'key1' );
fount.canResolve( [ 'key1', 'key2' ] );
```
## Injecting

@@ -161,9 +169,51 @@ 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.

fount.inject( [ 'one.a', 'two.b' ], function( a, b ) { ... } );
// alternate support for multiple containers
fount.inject( function( one_a, two_b ) { ... } );
```
## Configuration
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:
```javascript
{
[containerName]: {
[keyName]: [value],
[keyName]: {
[scope]: [value]
}
}
}
```
__example__
```javascript
fount( {
default: {
a: 1,
b: function() {
return 2;
}
},
other: {
c: { scoped: 3 },
d: { scoped: function() {
return 4;
}
},
e: { static: 5 },
f: { factory: function() {
return 6;
} }
}
} );
```
## Diagnostic
Right now this is pretty weak, but if you call `log`, Fount will dump the containers and scopes out so you can see what keys are present. Got ideas for more useful ways to troubleshoot? I'd love a PR :smile:!
## Tests & CI Mode
## Things to do soon
* Good error handling - returning clear error messages when a resolution/injection fails
* Running `gulp` starts both the `test` and `watch` tasks, so you'll see the tests re-run any time you save a file under `src/` or `spec/`.
* Running `gulp coverage` will run istanbul and create a `coverage/` folder.
* Running `gulp show-coverage` will run istanbul and open the browser-based coverage report.

@@ -6,8 +6,27 @@ var _ = require( 'lodash' );

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;
function backfillMissingDependency( name, containerName ) {
var mod = getLoadedModule( name ) || getModuleFromInstalls( name );
if ( mod ) {
var lifecycle = _.isFunction( mod ) ? 'factory' : 'static';
register( containerName, name, mod, lifecycle );
} else {
debug( 'Could not backfill dependency %s in in container %s', name, containerName );
}
return mod;
}
function canResolve( containerName, dependencies, scopeName ) {
return getMissingDependencies( containerName, dependencies, scopeName ).length === 0;
}
function checkDependencies( fn, dependencies ) {
var fnString = fn.toString();
if( /[(][^)]*[)]/.test( fnString ) ) {
if ( /[(][^)]*[)]/.test( fnString ) ) {
return ( _.isFunction( fn ) && !dependencies.length ) ?

@@ -21,2 +40,30 @@ trim( /[(]([^)]*)[)]/.exec( fnString )[ 1 ].split( ',' ) ) :

function configure( config ) {
_.each( config, function( val, containerName ) {
_.each( val, function( opt, key ) {
var dependency = opt;
var lifecycle;
if ( _.isObject( opt ) ) {
if ( opt.scoped ) {
lifecycle = 'scoped';
dependency = opt.scoped;
} else if ( opt.static ) {
lifecycle = 'static';
dependency = opt.static;
} else if ( opt.factory ) {
lifecycle = 'factory';
dependency = opt.factory;
} else {
dependency = undefined;
}
}
if ( !dependency ) {
dependency = opt;
lifecycle = _.isFunction( opt ) ? 'factory' : 'static';
}
register( containerName, key, dependency, lifecycle );
} );
} );
}
function container( name ) {

@@ -26,2 +73,54 @@ return ( containers[ name ] = containers[ name ] || { scopes: {} } );

function displayDependency( obj ) {
if ( _.isFunction( obj ) ) {
return obj.name || 'anonymous function';
} else if ( _.isString( obj ) || _.isNumber( obj ) || _.isArray( obj ) || _.isDate( obj ) ) {
return obj;
} else if ( _.isPlainObject( obj ) ) {
return '[Object Literal]';
} else {
return obj.constructor.name || '[Object]';
}
}
function findParent( mod ) {
if ( parent ) {
return parent;
}
if ( mod.parent ) {
return findParent( mod.parent );
} else {
parent = mod;
return mod;
}
}
function getLoadedModule( name ) {
var parent = findParent( module );
var regex = new RegExp( name );
var candidate = _.find( parent.children, function( child ) {
return regex.test( child.id ) && _.contains( child.id.split( '/' ), name );
} );
if ( candidate ) {
candidate.exports.__npm = candidate.exports.__npm || true;
return candidate.exports;
} else {
return undefined;
}
}
function getModuleFromInstalls( name ) {
var parent = findParent( module );
var installPath = _.find( parent.paths, function( p ) {
var modPath = path.join( p, name );
return fs.existsSync( modPath );
} );
var mod;
if ( installPath ) {
mod = require( path.join( installPath, name ) );
mod.__npm = mod.__npm || true;
}
return mod;
}
function getArgs( obj ) {

@@ -31,5 +130,40 @@ return Array.prototype.slice.call( obj );

function getMissingDependencies( containerName, dependencies, scopeName ) {
scopeName = scopeName || 'default';
containerName = containerName || 'default';
dependencies = _.isArray( dependencies ) ? dependencies : [ dependencies ];
return _.reduce( dependencies, function( acc, key ) {
if ( _.isArray( key ) ) {
var ctr = container( containerName );
key.forEach( function( k ) {
var originalKey = k;
var ctrName = containerName;
var parts = k.split( /[._]/ );
if ( parts.length > 1 ) {
ctr = container( parts[ 0 ] );
ctrName = parts[ 0 ];
k = parts[ 1 ];
}
if ( !ctr[ k ] && !backfillMissingDependency( key, ctrName ) ) {
acc.push( originalKey );
}
} );
} else {
var originalKey = key;
var parts = key.split( /[._]/ );
if ( parts.length > 1 ) {
containerName = parts[ 0 ];
key = parts[ 1 ];
}
if ( !container( containerName )[ key ] && !backfillMissingDependency( key, containerName ) ) {
acc.push( originalKey );
}
}
return acc;
}, [] );
}
function inject( containerName, dependencies, fn, scopeName ) {
scopeName = scopeName || 'default';
if( _.isFunction( dependencies ) ) {
if ( _.isFunction( dependencies ) ) {
scopeName = fn;

@@ -40,5 +174,11 @@ fn = dependencies;

dependencies = checkDependencies( fn, dependencies );
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( ', ' ) ) );
}
var args = dependencies.map( function( key ) {
var parts = key.split( '.' );
if( parts.length > 1 ) {
var parts = key.split( /[._]/ );
if ( parts.length > 1 ) {
containerName = parts[ 0 ];

@@ -53,2 +193,3 @@ key = parts[ 1 ];

function purge( containerName ) {
debug( 'purging container %s', containerName );
containers[ containerName ] = { scopes: {} };

@@ -58,2 +199,3 @@ }

function purgeAll() {
debug( 'purging all containers' );
containers = { scopes: {} };

@@ -63,2 +205,3 @@ }

function purgeScope( containerName, scopeName ) {
debug( 'purging container %s, scope %s', containerName, scopeName );
delete container( containerName ).scopes[ scopeName ];

@@ -71,3 +214,3 @@ }

var key = args[ 1 ];
var parts = key.split( '.' );
var parts = key.split( /[._]/ );
var dependencies = _.isArray( args[ 2 ] ) ? args[ 2 ] : [];

@@ -77,8 +220,9 @@ var fn = dependencies.length ? args[ 3 ] : args[ 2 ];

if( parts.length > 1 ) {
if ( parts.length > 1 ) {
containerName = parts[ 0 ];
key = parts[ 1 ];
}
if( _.isFunction( fn ) ) {
if ( _.isFunction( fn ) ) {
dependencies = checkDependencies( fn, dependencies );

@@ -88,3 +232,4 @@ } else {

}
debug( 'Registering key "%s" for container "%s" with %s lifecycle: %s', key, containerName, lifecycle, dependencies, fn );
debug( 'Registering key "%s" for container "%s" with %s lifecycle: %s',
key, containerName, lifecycle, getDisplay( fn ) );
var promise = wrappers[ lifecycle ]( containerName, key, fn, dependencies );

@@ -94,38 +239,15 @@ container( containerName )[ key ] = promise;

function canResolve( containerName, dependencies, scopeName ) {
scopeName = scopeName || 'default';
return _.all( dependencies, function( key ) {
if( _.isArray( key ) ) {
var ctr = container( containerName );
var vals = [];
key.forEach( function( k ) {
var originalKey = k;
var parts = k.split( '.' );
if( parts.length > 1 ) {
ctr = container( parts[ 0 ] );
k = parts[ 1 ];
}
vals.push( ctr[ k ] );
} );
return _.all( vals );
} else {
var parts = key.split( '.' );
if( parts.length > 1 ) {
containerName = parts[ 0 ];
key = parts[ 1 ];
}
return container( containerName )[ key ];
}
} );
}
function resolve( containerName, key, scopeName ) {
scopeName = scopeName || 'default';
if( _.isArray( key ) ) {
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 );
var hash = {};
key.forEach( function( k ) {
var originalKey = k;
var parts = k.split( '.' );
if( parts.length > 1 ) {
var parts = k.split( /[._]/ );
if ( parts.length > 1 ) {
ctr = container( parts[ 0 ] );

@@ -138,16 +260,27 @@ k = parts[ 1 ];

} else {
var parts = key.split( '.' );
if( parts.length > 1 ) {
var parts = key.split( /[._]/ );
if ( parts.length > 1 ) {
containerName = parts[ 0 ];
key = parts[ 1 ];
}
return container( containerName )[ key ]( scopeName );
return container( containerName )[ key ]( scopeName );
}
}
function trimString( str ) { return str.trim(); }
function trim( list ) {
return ( list && list.length ) ? _.filter( list.map( trimString ) ) : [];
function scope( containerName, name ) {
var ctr = container( containerName );
return ( ctr.scopes[ name ] = ctr.scopes[ name ] || {} );
}
function setModule( mod ) {
parent = mod;
}
function trimString( str ) {
return str.trim();
}
function trim( list ) {
return ( list && list.length ) ? _.filter( list.map( trimString ) ) : [];
}
function type( obj ) {

@@ -157,23 +290,23 @@ return Object.prototype.toString.call( obj );

function scope( containerName, name ) {
var ctr = container( containerName );
return ( ctr.scopes[ name ] = ctr.scopes[ name ] || {} );
}
var wrappers = {
factory: function ( containerName, key, value, dependencies ) {
factory: function( containerName, key, value, dependencies ) {
return function( scopeName ) {
if( _.isFunction( value ) && dependencies && canResolve( containerName, dependencies, scopeName ) ) {
var args = dependencies.map( function( key ) {
return resolve( containerName, key, scopeName );
} );
return whenFn.apply( value, args );
} else {
return when.promise( function ( resolve ) {
resolve( value );
} );
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 );
}
}
return when.promise( function( resolve ) {
resolve( value );
} );
};
},
scoped: function ( containerName, key, value, dependencies ) {
scoped: function( containerName, key, value, dependencies ) {
return function( scopeName ) {

@@ -185,6 +318,5 @@ var cache = scope( containerName, scopeName );

};
if( cache[ key ] ) {
if ( cache[ key ] ) {
return cache[ key ];
}
else if( _.isFunction( value ) && dependencies && canResolve( containerName, dependencies, scopeName ) ) {
} else if ( _.isFunction( value ) && dependencies && canResolve( containerName, dependencies, scopeName ) ) {
var args = dependencies.map( function( key ) {

@@ -195,4 +327,4 @@ return resolve( containerName, key, scopeName );

} else {
return when.promise( function ( resolve ) {
if( when.isPromiseLike( value ) ) {
return when.promise( function( resolve ) {
if ( when.isPromiseLike( value ) ) {
value.then( store );

@@ -209,3 +341,3 @@ } else {

var promise;
if( _.isFunction( value ) && dependencies && canResolve( containerName, dependencies ) ) {
if ( _.isFunction( value ) && dependencies && canResolve( containerName, dependencies ) ) {
var args = dependencies.map( function( key ) {

@@ -218,3 +350,5 @@ return resolve( containerName, key );

}
return function() { return promise; };
return function() {
return promise;
};
}

@@ -224,19 +358,29 @@ };

var fount = function( containerName ) {
return {
inject: inject.bind( undefined, containerName ),
register: register.bind( undefined, containerName ),
resolve: resolve.bind( undefined, containerName ),
purge: purgeScope.bind( undefined, containerName ),
purgeScope: purgeScope.bind( undefined, containerName )
};
if ( _.isObject( containerName ) ) {
configure( containerName );
} else {
return {
canResolve: canResolve.bind( undefined, containerName ),
inject: inject.bind( undefined, containerName ),
register: register.bind( undefined, containerName ),
resolve: resolve.bind( undefined, containerName ),
purge: purgeScope.bind( undefined, containerName ),
purgeScope: purgeScope.bind( undefined, containerName )
};
}
};
fount.canResolve = canResolve.bind( undefined, 'default' );
fount.inject = inject.bind( undefined, 'default' );
fount.register = register.bind( undefined, 'default' );
fount.resolve = resolve.bind( undefined, 'default' );
fount.purge = purgeScope.bind( undefined, 'default' );
fount.purge = purge.bind( undefined );
fount.purgeAll = purgeAll;
fount.purgeScope = purgeScope.bind( undefined, 'default' );
fount.log = function() { console.log( containers ); };
fount.setModule = setModule;
module.exports = fount;
fount.log = function() {
console.log( containers );
};
module.exports = fount;

Sorry, the diff of this file is not supported yet

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