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

easy-app

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

easy-app - npm Package Compare versions

Comparing version 0.0.2 to 0.1.0

component.json

302

index.js

@@ -1,301 +0,7 @@

var parseFnArgs = require('parse-fn-args')
var util = require('./lib/util')
module.exports = Container
exports = module.exports = require('./lib/container')
function Container () {
if (!(this instanceof Container)) {
return new Container
}
}
exports.nsconcat = util.nsconcat
function ThisObj (name) {
return function thisObj () {
if (this[name].__owner === this) return this[name]
this[name] = Object.create(thisObj.call(this.__proto__))
setOwner(this, name)
return this[name]
}
}
function setOwner (obj, prop) {
Object.defineProperty(obj[prop], '__owner', {
value: obj
})
}
Container.prototype.use = function (plugin) {
var fn = plugin
arguments[0] = this
fn.apply(this, arguments)
return this
}
Container.prototype.values = {}
setOwner(Container.prototype, 'values')
Container.prototype.thisValues = ThisObj('values')
Container.prototype.tasks = {}
setOwner(Container.prototype, 'tasks')
Container.prototype.thisTasks = ThisObj('tasks')
Container.prototype.aliases = {}
setOwner(Container.prototype, 'aliases')
Container.prototype.thisAliases = ThisObj('aliases')
Container.prototype.set = function (name, val) {
this.thisValues()[name] = val
return this
}
Container.prototype.get = function (name) {
var val = this.values[name]
if (val !== undefined) return val
if (this.aliases[name]) return this.get(this.aliases[name])
}
Container.prototype.importing = function () {
return this
}
Container.prototype.alias = function (from, to) {
this.thisAliases()[from] = to
return this
}
Container.prototype.def = function (layer, task, deps, fn) {
if (typeof task != 'string') { // allow layer omission
fn = deps
deps = task
task = layer
layer = null
}
if (typeof deps == 'function') { // allow implicit deps
fn = deps
deps = fn.deps || parseFnArgs(fn)
}
this.thisValues()[task] = undefined
this.thisTasks()[task] = {
fn: fn,
deps: deps,
layer: layer || this._layer,
name: task
}
return this
}
Container.prototype.at = function (layer, fn) {
this._layer = layer
try {
fn.call(this, this)
} finally {
this._layer = null
}
return this
}
Container.prototype.install = function (namespace, app, aliases) {
if (typeof namespace != 'string') {
aliases = app
app = namespace
namespace = ''
} else {
namespace += '_'
}
function mix (target, src, cb) {
cb = cb || function (val) { return val }
for (var key in src) {
target[namespace + key] = cb(src[key], key)
}
}
mix(this.thisValues(), app.values)
mix(this.thisTasks(), app.tasks, function (t) {
return {
fn: t.fn,
layer: t.layer,
deps: t.deps.map(function (dep) {
return dep == 'done' || dep == 'eval'
? dep
: namespace + dep
}),
namespace: namespace + (t.namespace || '')
}
})
mix(this.thisAliases(), app.aliases, function (alias) {
return namespace + alias
})
for (var key in aliases) {
this.alias(namespace + key, aliases[key] == '*' ? key : aliases[key])
}
return this
}
Container.prototype.layer = function (name) {
this.name = name
return this
}
Container.prototype.run = function () {
return Object.create(this)
}
Container.prototype.eval = function (task, cb) {
var val = this.values[task]
if (val !== undefined) {
if (cb) val instanceof Error
? cb.call(this, val)
: cb.call(this, null, val)
return
}
if (this.aliases[task]) {
this.eval(this.aliases[task], function (err, val) {
this.set(task, err || val)
cb.call(this, err, val)
})
return
}
var ev = '_eval_' + task
if (!this[ev]) {
var t = this.tasks[task]
if (!t) return cb && cb(new Error('Task ' + task + ' is not defined'))
new Evaluation(this, cb)
.task(task, t)
.start()
} else {
cb && this[ev].ondone(cb)
}
}
function Evaluation (container, cb) {
this.c = container
this.callbacks = []
this.deps = []
cb && this.ondone(cb)
}
Evaluation.prototype.ondone = function (cb) {
this.callbacks.push(cb)
}
Evaluation.prototype.task = function (name, def) {
this.t = def
this.name = name
this.setApp()
this.app['_eval_' + this.name] = this
return this
}
Evaluation.prototype.setApp = function () {
if (!this.t.layer) return this.app = this.c
var app = this.c
while (app.name && (app.name != this.t.layer || !app.hasOwnProperty('name'))) {
app = app.__proto__
}
this.app = app.name == this.t.layer ? app : this.c
}
Evaluation.prototype.start = function () {
this.evalDeps(0)
}
Evaluation.prototype.evalDeps = function (index) {
var sync = true
, deps = this.t.deps
, val
while (sync) {
var dep = deps[index]
if (!dep) return this.exec()
if (dep == 'done') {
this.async = true
this.deps[index++] = this.done.bind(this)
continue
}
if (dep == 'eval') {
this.deps[index++] = function (task, cb) {
var name = this.t.namespace ? this.t.namespace + task : task
this.app.eval(name, cb)
}.bind(this)
continue
}
val = this.app.values[dep]
if (val !== undefined) {
if (val instanceof Error) return this.done(val)
this.deps[index++] = val
continue
}
var done = false
this.app.eval(dep, function (err, val) {
if (err) return this.done(err)
done = true
this.deps[index++] = val
if (sync) return
this.evalDeps(index)
}.bind(this))
sync = done
}
}
Evaluation.prototype.exec = function () {
try {
if (this.async) {
this.t.fn.apply(this.app, this.deps)
} else {
this.done(null, this.t.fn.apply(this.app, this.deps))
}
} catch (e) {
this.done(e)
}
}
Evaluation.prototype.done = function (err, val) {
if (this.ended) {
console.error(
this.name
? 'Task <' + this.name + '> called its callback twice'
: 'Some evaluation called its callback twice'
)
if (err) {
console.error('Perhaps it happened because of exception in a task callback:')
err.stack ? console.error(err.stack) : console.error(String(err))
}
return
}
this.ended = true
if (err != null) {
if (!(err instanceof Error)) {
err = new Error(String(err))
}
err.task = err.task || this.name
val = err
} else {
val = val === undefined ? null : val
}
this.app.set(this.name, val)
this.app['_eval_' + this.name] = null // cleanup
for (var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].call(this.c, err, val)
}
}
exports.nssuffix = util.nssuffix
{
"name": "easy-app",
"version": "0.0.2",
"version": "0.1.0",
"description": "Simple and powerful container for applications",

@@ -22,4 +22,5 @@ "author": "Eldar Gabdullin <eldargab@gmail.com>",

"should": "*",
"test-log": "*"
"test-log": "*",
"benchmark": "*"
}
}

@@ -16,7 +16,7 @@ # easy-app

app.def('baz', function (bar) {
app.def('baz', function(bar) {
return bar * 2
})
app.def('foo', function (bar, baz) {
app.def('foo', function(bar, baz) {
return bar + baz

@@ -30,3 +30,3 @@ })

```javascript
app.eval('foo', function (err, foo) {
app.eval('foo', function(err, foo) {
foo.should.equal(30)

@@ -39,3 +39,3 @@ })

```javascript
app.def('config', function (done) {
app.def('config', function(done) {
fs.readFile('config', done)

@@ -49,3 +49,3 @@ })

```javascript
app.def('foo', ['bar', 'baz'], function (bar, baz) {
app.def('foo', ['bar', 'baz'], function(bar, baz) {
return bar + baz

@@ -67,6 +67,6 @@ })

// Not http_request, approval_request, etc
subapp.def('req', function (bar, baz) {})
subapp.def('req', function(bar, baz) {})
// Specify missing tasks.
subapp.importing( // currently noop
subapp.importing(
'bar',

@@ -86,3 +86,3 @@ 'baz'

```javascript
app.def('super_req', ['super_bar', 'super_baz'], function (bar, baz) {})
app.def('super_req', ['super_bar', 'super_baz'], function(bar, baz) {})
```

@@ -106,6 +106,9 @@

'bar': 'bar',
'baz': '*' // shortcut for 'baz':'baz'
'baz': 'baz'
})
```
But because `.install` setups aliases for undefined imports automatically
we could stick with just `app.install('super', subapp)`
## Layers

@@ -118,15 +121,15 @@

app.layer('app') // mark current instance to be app level
app.at('app', function () {
app.def('config', function (done) {
app.at('app', function() {
app.def('config', function(done) {
readJson('config.json', done)
})
app.def('db', function (config) {
app.def('db', function(config) {
return require('monk')(config.connection_string)
})
})
app.at('request', function () {
app.def('session', function (db, req, done) {
app.at('request', function() {
app.def('session', function(db, req, done) {
db.loadSession(req.cookie.session, done)
})
app.def('user', function (db, session, done) {
app.def('user', function(db, session, done) {
db.loadUser(session.username, done)

@@ -136,3 +139,3 @@ })

// ...
http.createServer(function (req, res) {
http.createServer(function(req, res) {
app

@@ -153,18 +156,28 @@ .run() // create next level instance

```javascript
app.def('level', 'task', function (a, b) {})
app.def('level', 'task', function(a, b) {})
```
## Misc
## Notes
### Error handling
All task errors both sync and async are catched. In addition `err.task`
property is set to the name of task which throwed an error.
All task errors both sync and async are catched. In addition `err._task`
property is set to the name of the task that throwed an error and `err._layer` is set
to the name of the nearest named layer.
### Control flow
All tasks are executed sequentally one after another
All tasks are executed sequentally one after another. Dependencies are evaluated
from left to right. You can rely on that.
### eval
It is convenient to specify pre-task things as an additional dependency. For example:
```javascript
app.def('secretDocument', function(authorized, db) {
return db.getSecret()
})
```
### Evaluation of arbitrary task from within task
There is another special case dependency called `eval`. No surprise that it is

@@ -178,3 +191,3 @@ similar to `app.eval()` but can be used within task and works for subapp case

.def('baz', baz)
.def('exec', function (task, eval, done) {
.def('exec', function(task, eval, done) {
eval(task, done)

@@ -190,2 +203,51 @@ })

## Doing things by convention
Sometimes you want to do things that while accomplished with
regular API require a lot of repetition. For example add security check for
all tasks with a certain name pattern or define subapp dependency depending on
it's namespace, etc. Eventually `.ontask()`, `.onsubapp()` hooks will be
provided for doing such sort of things, but now only `.onsubapp()` is ready.
```javascript
// Hooks are just methods, not an events
// .onsubapp() is called after subapp installation but before auto-aliasing
app.onsubapp = function(ns, app) {
// do your stuff here
// e.g
this.def(nsconcat(ns, 'foo'), createFoo(ns))
}
```
In addition there is some reflection API you might find useful:
```javascript
app.importing('foo', 'bar')
app.imports('foo') //=> true
app.imports() //=> ['foo', 'bar']
```
```javascript
app.set('foo', 'foo')
app.alias('bar', 'foo')
app.def('baz', baz)
app.defined('foo') //=> true
app.defined('bar') //=> true
app.defined('baz') //=> true
app.defined('qux') //=> false
```
```javascript
var nsconcat = require('easy-app').nsconcat
var nssuffix = require('easy-app').nssuffix
nsconcat('hello', 'world') //=> 'hello_world'
nsconcat('', 'world') //=> 'world'
nssuffix('hello', 'hello_world') //=> 'world'
nssuffix('foo', 'hello_world') //=> null
```
### .use()

@@ -196,3 +258,3 @@

```javascript
app.use(function plugin (container, param) {
app.use(function plugin(container, param) {
container.should.equal(app)

@@ -208,19 +270,28 @@ this.should.equal(app)

```shell
```
npm install easy-app
```
via component
```
component install eldargab/easy-app
```
## Related
### Special thanks
[make-flow](https://github.com/eldargab/make-flow) is an util with
similar ideas but intended to be just a simple control flow util rather than a
full blown container.
[easy-web](https://github.com/eldargab/easy-web) is a new web framework under
development on top of easy-app. Nearly ready but completely undocumented.
Ping me if you seriously plan to use easy-app in that context and interested in
some inspiration.
## Special thanks
This work intially inspired by
[The-Kiln](https://github.com/straszheimjeffrey/The-Kiln)
### make-flow
[make-flow](https://github.com/eldargab/make-flow) is a util with
similar ideas but intended to be just a simple control flow util rather than a
full blown container.
## License

@@ -227,0 +298,0 @@

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