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

clues

Package Overview
Dependencies
Maintainers
1
Versions
158
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

clues - npm Package Compare versions

Comparing version 0.0.7 to 1.0.0

26

clues.js

@@ -17,3 +17,3 @@ /**

clues.version = "0.0.7";
clues.version = "1.0.0";

@@ -30,4 +30,5 @@ function clues(logic,facts) {

function matchArgs(fn) {
if (fn.__args__) return fn.__args__;
var match = reArgs.exec(fn.prototype.constructor.toString());
return match[1].replace(/\s/g,'').split(",");
return fn.__args__ = match[1].replace(/\s/g,'').split(",");
}

@@ -70,3 +71,3 @@

fulfill : p.fulfill,
reject: function(e) { return p.reject(e);},
reject: p.reject,
callback : function(err,d) {

@@ -92,10 +93,9 @@ if (err) p.reject(err);

.then(function() {
try {
var value = self.wrap.call(context,fn,args);
if (value !== undefined) {
if (value.then) value.then(p.fulfill,p.reject);
else p.fulfill(value);
}
} catch(e) { p.reject(e);}
},function(err) {
var value = self.wrap.call(context,fn,args);
if (value !== undefined) {
if (value.then) value.then(p.fulfill,p.reject);
else p.fulfill(value);
}
})
.then(null,function(err) {
p.reject(err);

@@ -169,5 +169,3 @@ });

},
function(err) {
p.reject(err);
});
p.reject);
});

@@ -174,0 +172,0 @@ return p.promise;

@@ -5,2 +5,2 @@ /**

*/
(function(e){function t(e,r){return this instanceof t?(this.logic=e||("undefined"==typeof window?{}:window),this.facts=r||{},void 0):new t(e,r)}function r(e){var t=i.exec(""+e.prototype.constructor);return t[1].replace(/\s/g,"").split(",")}var n;"undefined"!=typeof module?(n=require("q"),module.exports=t):(n=e.Q,e.clues=t),t.version="0.0.7";var i=/function.*?\((.*?)\).*/;t.prototype.solve=function(e,t){var n,i=this,f=i.adapter,o=f.pending();if(t=t||{},"function"!=typeof e){if(n=e,t[n])return f.fulfilled(t[n]);if(void 0!==i.facts[n])return f.fulfilled(i.facts[n]);if(void 0===i.logic[n])return f.rejected({ref:n,err:"not defined"});if("function"!=typeof i.logic[n])return f.fulfilled(i.logic[n]);i.facts[n]=o.promise,o.promise.then(function(e){i.facts[n]=e}),e=i.logic[n]}var l={ref:n,self:i,local:t,facts:i.facts,promise:o.promise,fulfill:o.fulfill,reject:function(e){return o.reject(e)},callback:function(e,t){e?o.reject(e):o.fulfill(t)}};l.resolve=l.success=l.fulfill,l.error=l.reject;var c=r(e).filter(function(e){return e.length}).map(function(e){return"all"==e?i.all():l[e]||i.solve(e,t)});return this.join(c).then(function(){try{var t=i.wrap.call(l,e,c);void 0!==t&&(t.then?t.then(o.fulfill,o.reject):o.fulfill(t))}catch(r){o.reject(r)}},function(e){o.reject(e)}),o.promise.then(null,function(e){throw e.message&&(e=e.message),e.ref||(e={ref:n,err:e}),e})},t.prototype.wrap=function(e,t){return e.apply(this,t)},t.prototype.all=function(e){var t,r=this;return t=Object.keys(r.logic).map(function(t){return r.solve(t,e)}),r.join.call(this,t).then(function(){return r.facts})},t.prototype.as=function(e){var t=this,r=t.adapter.pending();return t.facts[e]=r.promise,function(n,i){n?r.reject(n):r.fulfill(i),t.facts[e]=i}},"undefined"!==n&&(t.prototype.adapter={fulfilled:n.resolve,rejected:n.reject,pending:function(){var e=n.defer();return{promise:e.promise,fulfill:e.resolve,reject:e.reject}}}),t.prototype.join=function(e){var t=e.length,r=this.adapter.pending();return t||r.fulfill([]),e.forEach(function(n,i){return n.then?(n.then(function(n){return e[i]=n,!(t-=1)&&r.fulfill(e)},function(e){r.reject(e)}),void 0):!(t-=1)&&r.fulfill(e)}),r.promise}})(this);
(function(e){function t(e,r){return this instanceof t?(this.logic=e||("undefined"==typeof window?{}:window),this.facts=r||{},void 0):new t(e,r)}function r(e){if(e.__args__)return e.__args__;var t=i.exec(""+e.prototype.constructor);return e.__args__=t[1].replace(/\s/g,"").split(",")}var n;"undefined"!=typeof module?(n=require("q"),module.exports=t):(n=e.Q,e.clues=t),t.version="0.0.7";var i=/function.*?\((.*?)\).*/;t.prototype.solve=function(e,t){var n,i=this,f=i.adapter,l=f.pending();if(t=t||{},"function"!=typeof e){if(n=e,t[n])return f.fulfilled(t[n]);if(void 0!==i.facts[n])return f.fulfilled(i.facts[n]);if(void 0===i.logic[n])return f.rejected({ref:n,err:"not defined"});if("function"!=typeof i.logic[n])return f.fulfilled(i.logic[n]);i.facts[n]=l.promise,l.promise.then(function(e){i.facts[n]=e}),e=i.logic[n]}var o={ref:n,self:i,local:t,facts:i.facts,promise:l.promise,fulfill:l.fulfill,reject:l.reject,callback:function(e,t){e?l.reject(e):l.fulfill(t)}};o.resolve=o.success=o.fulfill,o.error=o.reject;var u=r(e).filter(function(e){return e.length}).map(function(e){return"all"==e?i.all():o[e]||i.solve(e,t)});return this.join(u).then(function(){var t=i.wrap.call(o,e,u);void 0!==t&&(t.then?t.then(l.fulfill,l.reject):l.fulfill(t))}).then(null,function(e){l.reject(e)}),l.promise.then(null,function(e){throw e.message&&(e=e.message),e.ref||(e={ref:n,err:e}),e})},t.prototype.wrap=function(e,t){return e.apply(this,t)},t.prototype.all=function(e){var t,r=this;return t=Object.keys(r.logic).map(function(t){return r.solve(t,e)}),r.join.call(this,t).then(function(){return r.facts})},t.prototype.as=function(e){var t=this,r=t.adapter.pending();return t.facts[e]=r.promise,function(n,i){n?r.reject(n):r.fulfill(i),t.facts[e]=i}},"undefined"!==n&&(t.prototype.adapter={fulfilled:n.resolve,rejected:n.reject,pending:function(){var e=n.defer();return{promise:e.promise,fulfill:e.resolve,reject:e.reject}}}),t.prototype.join=function(e){var t=e.length,r=this.adapter.pending();return t||r.fulfill([]),e.forEach(function(n,i){return n.then?(n.then(function(n){return e[i]=n,!(t-=1)&&r.fulfill(e)},r.reject),void 0):!(t-=1)&&r.fulfill(e)}),r.promise}})(this);
{
"name": "clues",
"version": "0.0.7",
"description": "Lightweight dependency solver for aync functions, based on promises.",
"version": "1.0.0",
"description": "Lightweight dependency solver for aync functions, using promises.",
"keywords": [

@@ -6,0 +6,0 @@ "asynchronous",

# clues.js
If you haven't got a clue, then this library might be exactly what you need!
[Promises](https://github.com/promises-aplus) provide a very effective mechanism to construct complex interactions between asynchronous functions. Most promise libraries focus on the promise object itself, and leave the actual structuring of complex logic up to the user.
Promises provide a very effective mechanism to construct complex interactions between asynchronous functions. However the specifications and current implementations focus on the promises themselves, not how they might be structured and efficiently linked together. **clues.js** is a promising lightweight asynchronous library with a twist. Inspired by [queue.js](https://github.com/mbostock/queue), [require.js](http://requirejs.org/) and [async.js](https://github.com/caolan/async), this library resolves dependencies, as needed, between asynchronous functions, memoizing the output in a "fact table" along with any static inputs supplied.
**clues.js** simplifies structuring of long complex chains of logic by recursively and automatically solving dependencies for any given logical operation. Output of any logic is memoized in a fact table, for a quick reuse
The first secret ingredient of clues.js is the inspection of function signatures, where argument names are parsed and matched to corresponding facts and logic functions (or local object variables). The second secret ingredient is the use of promises for all resolutions, callbacks and returns are (using the engine/adaptor of your choice).
The first secret ingredient of clues.js is the inspection of function signatures. Argument names of supplied functions are parsed and matched to corresponding facts and logic functions (by name). The second secret ingredient is the use of promises for all resolutions, callbacks and returns (using the engine/adapter of your choice).
Each argument to a logic function needs to have a fact with the same name or a logic function if that fact hasn't been determined yet. If a `fact` with the same name as a function argument already exists (either previously resolved, or supplied directly), it is simply passed on as an argument value to the function. If a fact is unresolved (i.e. undefined), a logic function with same name is executed to resolve the fact value, before passing it on to the original function for execution. If an argument name can neither be matched with a fact nor a logic function/value an error is raised.
Each argument of a logic function needs to have either a fact with the same name or a logic function with that name (if fact hasn't been determined yet). If a `fact` with the same name as a function argument already exists (either previously resolved, or supplied directly), it is simply passed on as an argument value to the function. If a fact is unresolved (i.e. undefined), a logic function with same name is executed to resolve the fact value, before passing it on to the original function for execution. If an argument name can neither be matched with a fact nor a logic function/value an error is raised.
Each logic function will only execute when it's input arguments values are known (as a `fact`). Each unknown input value will start off a `logic` function (by same name). When a named logic function is executed, a corresponding fact is created as a promise on the results. When the function has been resolved, the fact table is updated and the promise is fulfilled, allowing any derived functions to proceed.
Each logic function will execute only once (if at all) in an clues object. Multiple requests for the same logic will simply attach to the original request callback and once the output is known, any further requests will simply return the resolved `fact` (or an error, respectively)
Each logic function will execute only once (if at all) in an clues object. Multiple requests for the same logic will simply attach to the initial promise, and once the output is known, any further requests will simply return the resolved `fact` (or an error, respectively)
A clues object can be long-running, building uo/memoizing all the facts as required or a quick temporary scaffold that is discarded once a particular answer has been recursively solved from given inputs.
## API Reference
### `clues([logic],[facts])`
Creates a new clues object based on a particular logic (set of functions and values by reference) and facts (ref: value). Logic and fact objects can be defined/modified later as they are public variables of the clues object.
Creates a new clues object based on a particular logic (set of functions and values by reference) and facts (associative arrays of known values). Logic and fact objects can be defined/modified later as they are public variables of the clues object.
The logic object is used as read-only (i.e. any results will only alter fact object, not the logic object), allowing the same logic definitions to be reused for multiple clues objects (each with a separate fact space). Clues object can furthermore be chained by requiring any logic function of one clues object to use .exec() function of another.
The logic object is used as read-only (i.e. any results will **only** alter fact object, not the logic object), allowing the same logic definition to be reused for multiple clues objects (each with a separate fact space). Clues object can furthermore be chained by requiring any logic function of one clues object to use .exec() function of another.

@@ -24,15 +26,13 @@ If no logic is provided to clues in a browser environment, it will use the global object (Window)

### `clues.solve(function(arg1,arg2...) { .... } ,[local_vars])`
This schedules an execution of the supplied function. The argument names of the function will be parsed and matched to facts and logic within the instance object by argument name. Any arguments that point to neither a fact nor logic will result in an error. The supplied function is essentially a callback function that is executed when the inputs are known.
This schedules an execution of the supplied function. The argument names of the function will be parsed and matched to facts and logic within the instance object by argument name. Any arguments that point to neither a fact nor logic (nor locals) will result in an error. The supplied function is essentially a callback function that is executed when the inputs are known.
The second argument (optional) allows local variables that will be used, and have priority, against facts and logic. The is to provide the flexibility to have functions respond to request specific variables, such as a response stream or to override any previously detemined facts. Please note however, that locals should really be used at end-points in logic, to ensure that locals do not contaminate derived facts.
The second argument (optional) allows local variables that will be used, and have priority, against facts and logic. The is to provide the flexibility to have functions respond to request specific variables, such as a response stream or to override any previously determined facts. Please note however, that locals should really be used at end-points in logic, to ensure that locals do not contaminate derived facts.
The solve function returns a promise. As the main operations take place in the user supplied function, the subsequent promise might be of less interest, except for error handling.
The solve function always returns a promise. As the main operations take place in the user supplied function, the subsequent promise might be of less interest, except for error handling.
### `clues.solve("name",[local_vars])`
The exec function can also be called with a string name as first parameter and an optional locals object as the second parameter. This is essentially the same as calling clues exec with a function with only one variable (i.e. name) and is ideal if you need to only work with one fact object.
The exec function can also be called with a string name as first parameter and an optional locals object as the second parameter. This is essentially the same as calling clues exec with a function with only one variable (i.e. name) and is ideal if you need to only work with one fact variable at a time.
As before the solve function returns a promise on the results and a natural step would be to chain into .then(resolveCb,ErrorCb) for further processing.
### `clues.logic = {}`
Key/value dictionary of logic functions and/or values. Functions in the logic object must only contain arguments names that correspond to either facts or as other logic functions/values. Each logic function must execute a callback at some point with the resolved value or an error. The typical way to execute the callback is to call `this.callback(err,value)` ensuring that the `this` object passed at the top is stored as a local variable if the results are returned from a deeper scope.
Key/value dictionary of logic functions and/or values. Functions in the logic object must only contain arguments names that correspond to either facts or as other logic functions/values. Each logic function must either return a value/promise, or execute a callback/resolve/error at some point with the resolved value or an error. A classical way to execute the callback is to call `this.callback(err,value)` ensuring that the `this` object passed at the top is stored as a local variable if the results are returned from a deeper scope.

@@ -43,17 +43,27 @@ ##### `this` context for logic functions

`this.facts` is a reference to the current facts object of the clues instance (should not be used really, except to overwrite other facts)
* `this.facts` is a reference to the current facts object of the clues instance (should not be used really, except to overwrite other facts)
`this.all` is same as `this.facts` except it forces a complete exec() of all unresolved definitions in the logic object.
* `this.all` is same as `this.facts` except it forces a complete exec() of all unresolved definitions in the logic object. This operation will fail unless all logic functions can be resolved.
`this.callback` is the standard callback that requires `(err,value)` as parameters
* `this.callback` is the standard callback that requires `(err,value)` as parameters
`this.success` is syntax sugar for `this.callback(null,value)`
* `this.resolve` is syntax sugar for `this.callback(null,value)`
`this.error` is syntax sugar for `this.callback(error,null)`
* `this.reject` is syntax sugar for `this.callback(error,null)`
Additionally we have `this.resolve` and `this.reject` for those who like jquery promises way of resolving outstanding requests.
* `this.local` contains an object of any local variables supplied for the execution (if any)
* `this.promise` contains the promise of the default deferred object used in the standard callbacks (i.e. resolve, reject etc).
Additionally we have `this.success` and `this.fulfill` aliases for resolve and `this.error` as an alias for reject.
Any logic function must do one of the following:
* Return a value (that will be the immediate fulfillment value of the subsequent promise)
* Return a custom promise object (the default promise object will in this be ignored)
* Return nothing (undefined) but at some point execute a callback (i.e. callback/resolve/reject).
A function that returns nothing and never executes any of the callback functions will hang (unless a timeout has been defined in the prototype wrapper).
##### Bonus level - this properties as reserved argument names
Most asynchronous functions lose the context of the original `this` object requiring the programmer to store `this` as a local `that` or `self` at the top of the function. In an attempt to eliminate this tedious requirement, all properties of `this` object are injected as function arguments if/when their names appear as arguments in the function signature. This obviously means that those names are reserved and cannot be used as names of facts or custom logic.
Most asynchronous functions lose the context of the original `this` object requiring the programmer to either bind functions or store `this` as a local `that` or `self` at the top of the function. In an attempt to eliminate this tedious requirement, all properties of `this` object are injected as function arguments if/when their names appear as arguments in the function signature. This obviously means that those names are reserved and cannot be used as names of facts or custom logic.

@@ -108,5 +118,12 @@ Example:

### `clues.prototype.adaptor`
### `clues.prototype.adapter`
Clues.js is designed to work with any Promise library that supports the [Promises/A+](https://github.com/promises-aplus/promises-spec) specification through adaptors. By default we use [Q](https://github.com/kriskowal/q) as it works well in the browser as well as node.js. By overwriting the prototype object (or instance property) other libraries can be easily applied.
Additionally, using the `clues.prototype.adapter.defer()` for any custom promises in the logic functions will ensure that if/when you change the underlying promise library, the logic code will follow suit.
### `clues.prototype.wrapper`
Once function arguments have been resolved a function is executed. The function execution is passed through a prototype wrapper function that, by default, simply executes the function. This wrapper can be overwritten in the prototype or class objects to i.e. add timeouts and other functionality.
For database caching, external wrappers might be more efficient (i.e. wrapping each logic function) as the prototype wrapper requires all inputs to be resolved.
## Hints and tips

@@ -113,0 +130,0 @@ * Asynchronous functions must return nothing (i.e. return undefined) and call callback, resolve or reject at some point. Any function with a return value will be assumed to be synchronous (promise is fulfilled on that returned value), regardless of any subsequent calls to a callback.

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