Socket
Socket
Sign inDemoInstall

sdic

Package Overview
Dependencies
8
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.3.0 to 1.4.0

441

container.js

@@ -12,7 +12,7 @@ const fs = require('fs');

const throwError = (err) => {
if (err instanceof Error) {
throw err;
} else {
throw new Error(err);
}
if (err instanceof Error) {
throw err;
} else {
throw new Error(err);
}
};

@@ -23,26 +23,26 @@

module.exports = (basepath) => {
let basePathRegexp = new RegExp('^' + basepath);
let extensions = Object.keys(require('module')._extensions);
let basePathRegexp = new RegExp('^' + basepath);
let extensions = Object.keys(require('module')._extensions);
return (allowedExtensions = 'js|json|coffee') => {
return (allowedExtensions = 'js|json|coffee') => {
let factories = {};
let factories = {};
let loadDir = (basename, dir, opts = {}) => {
delete opts.alias; // if alias is used for a folder, do not pass it to loadFile fn, it'd damage module name
// load files from given path
let files = (opts.recursive === false) ? fs.readdirSync(dir) : readDirR(dir);
let loadDir = (basename, dir, opts = {}) => {
delete opts.alias; // if alias is used for a folder, do not pass it to loadFile fn, it'd damage module name
// load files from given path
let files = (opts.recursive === false) ? fs.readdirSync(dir) : readDirR(dir);
if (opts.filter) {
files = files.filter(file => (new RegExp(opts.filter)).test(file));
}
if (opts.filter) {
files = files.filter(file => (new RegExp(opts.filter)).test(file));
}
for (let i = 0; i < files.length; i++) {
loadFile(_path.join(dir, files[i]), _path.join(basename, '/', files[i]), opts);
}
};
for (let i = 0; i < files.length; i++) {
loadFile(_path.join(dir, files[i]), _path.join(basename, '/', files[i]), opts);
}
};
let createModuleName = (initialName, relPath, opts = {}) => {
let createModuleName = (initialName, relPath, opts = {}) => {
let moduleName = initialName;
if ('alias' in opts && !(_isString(opts.alias) && /^[a-zA-Z_$]{1}[a-zA-Z0-9_$]+$/.test(opts.alias))) {
if ('alias' in opts && !(_isString(opts.alias) && /^[a-zA-Z_$]{1}[a-zA-Z0-9_$]+$/.test(opts.alias))) {
return throwError(`Invalid alias: ${opts.alias}`);

@@ -85,23 +85,27 @@ }

if (opts.es6 === true) {
return moduleName;
}
return moduleName.charAt(0).toLowerCase() + moduleName.substr(1);
};
};
let loadFile = (file, relPath = '', opts = {}) => {
if (allowedExtensions && !(allowedExtensions.includes(file.match(/\w+$/)[0]))) return;
if (Array.isArray(opts.ignore) && opts.ignore.length) {
if (opts.ignore.find(pattern => (new RegExp(pattern)).test(file.replace(basePathRegexp, ''))) !== undefined) {
return;
}
}
let loadFile = (file, relPath = '', opts = {}) => {
if (allowedExtensions && !(allowedExtensions.includes(file.match(/\w+$/)[0]))) return;
if (Array.isArray(opts.ignore) && opts.ignore.length) {
if (opts.ignore.find(pattern => (new RegExp(pattern)).test(file.replace(basePathRegexp, ''))) !== undefined) {
return;
}
}
let moduleFile = file.replace(/\.\w+$/, '');
let moduleName = createModuleName(_path.basename(moduleFile), relPath, opts);
let moduleFile = file.replace(/\.\w+$/, '');
let moduleName = createModuleName(_path.basename(moduleFile), relPath, opts);
// Register module
let module = require(moduleFile);
if (_isPlainObject(module)) {
let content = fs.readFileSync(file);
if (!content) {
return throwError(`Cannot load file contents: ${moduleFile}`);
}
// Register module
let module = require(moduleFile);
if (_isPlainObject(module)) {
let content = fs.readFileSync(file);
if (!content) {
return throwError(`Cannot load file contents: ${moduleFile}`);
}

@@ -114,3 +118,3 @@ content = content.toString();

container.register(
key === 'default' ? moduleName : createModuleName(key, relPath, opts),
key === 'default' ? moduleName : createModuleName(key, relPath, _extend(opts, {es6: true})),
module[key],

@@ -124,43 +128,43 @@ _extend(opts, {dependencies: resolveArguments(module[key])})

content = null;
} else {
content = null;
} else {
container.register(moduleName, module, opts);
}
};
}
};
let resolveArguments = (fn) => {
// match argument list
return getParamNames(fn).filter(String).map((v) => v.trim())
};
let resolveArguments = (fn) => {
// match argument list
return getParamNames(fn).filter(String).map((v) => v.trim())
};
let resolveCacheFlag = (name, visited = []) => {
let resolveCacheFlag = (name, visited = []) => {
// check for circular dependencies
if (visited.includes(name)) {
visited.push(name);
return throwError(`Circular dependency: ${visited.join(' > ')}`);
}
// check for circular dependencies
if (visited.includes(name)) {
visited.push(name);
return throwError(`Circular dependency: ${visited.join(' > ')}`);
}
visited.push(name);
visited.push(name);
// if any of factory's dependencies has cache flag set to false - inherit it
let factory = factories[name];
if (!factory) {
return throwError(`Dependency does not exist: ${name} (${visited.join(' > ')})`);
}
// if any of factory's dependencies has cache flag set to false - inherit it
let factory = factories[name];
if (!factory) {
return throwError(`Dependency does not exist: ${name} (${visited.join(' > ')})`);
}
if (factory.opts.cache === false) return false;
if (factory.opts.cache === false) return false;
if (factory.dependencies.length > 0) {
for (let i = 0; i < factory.dependencies.length; i++) {
try {
if (!resolveCacheFlag(factory.dependencies[i], JSON.parse(JSON.stringify(visited)))) return false;
} catch (e) {
return throwError(e);
}
}
}
if (factory.dependencies.length > 0) {
for (let i = 0; i < factory.dependencies.length; i++) {
try {
if (!resolveCacheFlag(factory.dependencies[i], JSON.parse(JSON.stringify(visited)))) return false;
} catch (e) {
return throwError(e);
}
}
}
return true;
};
return true;
};

@@ -175,182 +179,187 @@ let makeClassInstance = (constructor, args) => {

let getModuleInstance = (name, overrides = {}, visited = []) => {
let getModuleInstance = (name, overrides = {}, visited = []) => {
// check for circular dependencies
if (visited.includes(name)) {
visited.push(name);
return throwError(`Circular dependency: ${visited.join(' > ')}`);
}
// check for circular dependencies
if (visited.includes(name)) {
visited.push(name);
return throwError(`Circular dependency: ${visited.join(' > ')}`);
}
visited.push(name);
visited.push(name);
// try to retrieve factory
let factory = factories[name];
if (!factory) {
return throwError(`Module does not exist: ${name}`);
}
// try to retrieve factory
let factory = factories[name];
if (!factory) {
return throwError(`Module does not exist: ${name}`);
}
// resolve if an instance should be cached
if (!('cache' in factory.opts) || factory.opts.cache === null) {
factory.opts.cache = resolveCacheFlag(name);
}
// resolve if an instance should be cached
if (!('cache' in factory.opts) || factory.opts.cache === null) {
factory.opts.cache = resolveCacheFlag(name);
}
let storeInstance = _isEmpty(overrides) && factory.opts.cache;
let storeInstance = _isEmpty(overrides) && factory.opts.cache;
// instance already created - return
if (factory.instance && storeInstance) {
return factory.instance;
}
// instance already created - return
if (factory.instance && storeInstance) {
return factory.instance;
}
// resolve factory arguments
let args = factory.dependencies.map((dependency) => {
if (dependency in overrides) {
return overrides[dependency];
}
// resolve factory arguments
let args = factory.dependencies.map((dependency) => {
if (dependency in overrides) {
return overrides[dependency];
}
return getModuleInstance(dependency, overrides, JSON.parse(JSON.stringify(visited)));
});
return getModuleInstance(dependency, overrides, JSON.parse(JSON.stringify(visited)));
});
// create instance
let instance;
try {
try {
// try to create instance of functional module
instance = factory.fn.apply(factory, args);
} catch (err) {
if (!/Cannot call a class as a function/.test(err.message)) {
throw err;
}
let instance;
// try to create instance of class module
instance = makeClassInstance(factory.fn, args);
}
} catch (err) {
err.message = `Cannot create an instance of: ${name}. Error: ${err.message}`;
return throwError(err);
}
if (factory.opts.isConstructor) {
instance = factory.fn;
} else {
try {
try {
// try to create instance of functional module
instance = factory.fn.apply(factory, args);
} catch (err) {
if (!/Cannot call a class as a function/.test(err.message)) {
throw err;
}
// store instance in cache
if (storeInstance) {
factory.instance = instance;
// try to create instance of class module
instance = makeClassInstance(factory.fn, args);
}
} catch (err) {
err.message = `Cannot create an instance of: ${name}. Error: ${err.message}`;
return throwError(err);
}
}
return instance;
};
// store instance in cache
if (storeInstance) {
factory.instance = instance;
}
// PUBLIC INTERFACE
let container = {
getAll: () => factories,
return instance;
};
get: (name, overrides = {}) => getModuleInstance(name, overrides),
// PUBLIC INTERFACE
let container = {
getAll: () => factories,
getByTag: (tag) => {
let instances = {};
for (let key in factories) {
if (factories[key].opts.tags.includes(tag)) {
instances[key] = container.get(key);
}
}
get: (name, overrides = {}) => getModuleInstance(name, overrides),
return instances;
},
getByTag: (tag) => {
let instances = {};
for (let key in factories) {
if (factories[key].opts.tags.includes(tag)) {
instances[key] = container.get(key);
}
}
register: (name, fn, opts = {}) => {
if (fn === undefined) {
return throwError('Unable to register empty (undefined) module');
}
return instances;
},
// throw exception if service already exists
if (name in factories) {
return throwError(`Module is already registered: ${name}`);
}
register: (name, fn, opts = {}) => {
if (fn === undefined) {
return throwError('Unable to register empty (undefined) module');
}
opts = _extend({cache: null, tags: []}, opts);
// remove folder opts
['recursive', 'reverseName', 'ignore', 'filter'].map(opt => delete opts[opt]);
// throw exception if service already exists
if (name in factories) {
return throwError(`Module is already registered: ${name}`);
}
// store service for later
if (_isFunction(fn)) {
factories[name] = {
fn: fn,
dependencies: opts.dependencies ? opts.dependencies : resolveArguments(fn),
opts: opts
};
} else {
factories[name] = {
fn: () => JSON.parse(JSON.stringify(fn)),
dependencies: [],
opts: opts
};
}
},
opts = _extend({cache: null, tags: []}, opts);
// remove folder opts
['recursive', 'reverseName', 'ignore', 'filter'].map(opt => delete opts[opt]);
load: (path, opts = {}) => {
// store service for later
if (_isFunction(fn)) {
factories[name] = {
fn: fn,
dependencies: opts.dependencies ? opts.dependencies : resolveArguments(fn),
opts: opts
};
} else {
factories[name] = {
fn: () => JSON.parse(JSON.stringify(fn)),
dependencies: [],
opts: opts
};
}
},
if ('prefix' in opts && !(_isString(opts.prefix) && /^[a-zA-Z_$]{1}[a-zA-Z0-9_$]+$/.test(opts.prefix))) {
throwError(`Invalid prefix: ${opts.prefix}`);
}
load: (path, opts = {}) => {
if ('postfix' in opts && !(_isString(opts.postfix) && /^[a-zA-Z0-9_$]+$/.test(opts.postfix))) {
throwError(`Invalid postfix: ${opts.postfix}`)
}
if ('prefix' in opts && !(_isString(opts.prefix) && /^[a-zA-Z_$]{1}[a-zA-Z0-9_$]+$/.test(opts.prefix))) {
throwError(`Invalid prefix: ${opts.prefix}`);
}
// resolve absolute file path
let possibleFiles = [
path,
_path.join(basepath, path)
];
if ('postfix' in opts && !(_isString(opts.postfix) && /^[a-zA-Z0-9_$]+$/.test(opts.postfix))) {
throwError(`Invalid postfix: ${opts.postfix}`)
}
extensions.forEach((ext) => {
possibleFiles.push(path + ext);
possibleFiles.push(_path.join(basepath, path + ext));
});
// resolve absolute file path
let possibleFiles = [
path,
_path.join(basepath, path)
];
let realpath;
for (let i = 0; i < possibleFiles.length; i++) {
if (fs.existsSync(possibleFiles[i])) {
realpath = fs.realpathSync(possibleFiles[i]);
break;
}
}
extensions.forEach((ext) => {
possibleFiles.push(path + ext);
possibleFiles.push(_path.join(basepath, path + ext));
});
if (typeof realpath === 'undefined') {
return throwError(`Unable to load file: ${path}`);
}
let realpath;
for (let i = 0; i < possibleFiles.length; i++) {
if (fs.existsSync(possibleFiles[i])) {
realpath = fs.realpathSync(possibleFiles[i]);
break;
}
}
// load particular file or directory
if (fs.statSync(realpath).isDirectory()) {
if ('alias' in opts) {
if (!([null, false, undefined, ''].includes(opts.alias) || (_isString(opts.alias) && /^[a-zA-Z_$]{1}[a-zA-Z0-9_$\-]+$/.test(opts.alias)))) {
return throwError(`Invalid alias: ${opts.alias}`);
}
}
loadDir('alias' in opts ? (opts.alias || '') : _path.basename(realpath), realpath, opts);
} else {
loadFile(realpath, '', opts);
}
},
if (typeof realpath === 'undefined') {
return throwError(`Unable to load file: ${path}`);
}
override: (name, fn, opts = {}) => {
if (name in factories) {
delete factories[name];
}
// load particular file or directory
if (fs.statSync(realpath).isDirectory()) {
if ('alias' in opts) {
if (!([null, false, undefined, ''].includes(opts.alias) || (_isString(opts.alias) && /^[a-zA-Z_$]{1}[a-zA-Z0-9_$\-]+$/.test(opts.alias)))) {
return throwError(`Invalid alias: ${opts.alias}`);
}
}
loadDir('alias' in opts ? (opts.alias || '') : _path.basename(realpath), realpath, opts);
} else {
loadFile(realpath, '', opts);
}
},
container.register(name, fn, opts);
},
override: (name, fn, opts = {}) => {
if (name in factories) {
delete factories[name];
}
unregister: (name) => {
delete factories[name];
},
container.register(name, fn, opts);
},
clear: () => {
factories = {};
container.register('container', container);
}
};
unregister: (name) => {
delete factories[name];
},
// register itself as a service
container.register('container', container);
clear: () => {
factories = {};
container.register('container', container);
}
};
return container;
}
// register itself as a service
container.register('container', container);
return container;
}
};
{
"name": "sdic",
"version": "1.3.0",
"version": "1.4.0",
"description": "Simple dependency injection container",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -43,3 +43,4 @@ # SDIC: Simple Dependency Injection Container

* deduplicate - remove multiple same string occurences (default: false)
* uppercaseFirst - create a module name with uppercased first letter (default: false, module name starts with lowercased letter)
* uppercaseFirst - create a module name with uppercased first letter (default: false - module name starts with lowercased letter)
* isConstructor - loaded module is a constructor, load and return it as a constructor, do return an instances (default: false - modules as singletons by default)

@@ -172,2 +173,21 @@ ```javascript

**ES6 note:** container returns instances of modules by default (aka singletons). If you want to register a class (constructor function), you have to use option: `isConstructor: true`
```javascript
class FooBar {}
container.register('FooBar', FooBar);
container.get('FooBar'); // --> returns an instance of FooBar (default behaviour)
```
```javascript
class FooBar {}
container.register('FooBar', FooBar, {isConstructor: true});
container.get('FooBar'); // --> returns class FooBar
```
```javascript
// all modules will be loaded as constructors
container.load('/path/to/constructors_folder', {isConstructor: true});
```
### Manual module registration

@@ -174,0 +194,0 @@

@@ -1,2 +0,2 @@

export const FirstFunctionalService = () => {
export const firstFunctionalService = () => {
return {

@@ -7,3 +7,3 @@ method: () => ({passed: true})

export function SecondFunctionalService (fooService) {
export function secondFunctionalService (fooService) {
return {

@@ -10,0 +10,0 @@ method: () => fooService.method()

@@ -169,7 +169,7 @@ const expect = require('chai').expect;

expect(container.getAll()).to.contain.all.keys(['firstFunctionalService', 'secondFunctionalService', 'classService', 'services']);
expect(container.getAll()).to.contain.all.keys(['firstFunctionalService', 'secondFunctionalService', 'ClassService', 'services']);
expect(Object.keys(container.getAll()).length).to.eql(6); // 5 + container itself
expect(container.get('firstFunctionalService').method()).to.deep.equal({passed: true});
expect(container.get('secondFunctionalService').method()).to.deep.equal({passed: true});
expect(container.get('classService').method()).to.deep.equal({passed: true});
expect(container.get('ClassService').method()).to.deep.equal({passed: true});
expect(container.get('services').method()).to.deep.equal({passed: true}); // default export

@@ -193,3 +193,20 @@ });

});
it('respects isConstructor flag', () => {
container.register('fooService', () => ({method: () => ({passed: true})}));
container.load('./named-exports/services', {isConstructor: true});
const ClassService = container.get('ClassService');
const instance = new ClassService();
expect(instance).to.be.an.instanceof(ClassService);
class AnotherClass {
}
container.register('AnotherClass', AnotherClass, {isConstructor: true});
const AnotherClassPtr = container.get('AnotherClass');
const anotherInstance = new AnotherClassPtr();
expect(anotherInstance).to.be.an.instanceof(AnotherClass);
});
});
});
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc