Comparing version 3.1.2 to 3.1.3
12
clues.js
@@ -69,3 +69,3 @@ (function(self) { | ||
if (typeof fn === 'object' && fn.length && typeof fn[fn.length-1] == 'function') { | ||
if (fn.length > 1 && (typeof(fn[0]) === 'object' || typeof(fn[0]) == 'function')) { | ||
if (fn.length > 1 && (typeof(fn[0]) === 'object' || typeof(fn[0]) == 'function') && !fn[0].length) { | ||
var obj = fn[0]; | ||
@@ -85,3 +85,3 @@ fn = fn.slice(1); | ||
// If the logic reference is not a function, we simply return the value | ||
if (typeof fn !== 'function' || (ref && ref[0] === '$')) return clues.Promise.fulfilled(fn); | ||
if (typeof fn !== 'function' || (ref && ref[0] === '$')) return clues.Promise.resolve(fn); | ||
@@ -96,7 +96,7 @@ args = (args || matchArgs(fn)) | ||
if (arg === '$caller') | ||
res = clues.Promise.fulfilled(caller); | ||
res = clues.Promise.resolve(caller); | ||
else if (arg === '$fullref') | ||
res = clues.Promise.fulfilled(fullref); | ||
res = clues.Promise.resolve(fullref); | ||
else if (arg === '$global') | ||
res = clues.Promise.fulfilled($global); | ||
res = clues.Promise.resolve($global); | ||
} | ||
@@ -136,2 +136,2 @@ | ||
})(this); | ||
})(this); |
{ | ||
"name": "clues", | ||
"version": "3.1.2", | ||
"version": "3.1.3", | ||
"description": "Lightweight logic tree solver using promises.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -382,3 +382,3 @@ **clues.js** is a lean-mean-promisified-getter-machine that crunches through any javascript objects, including complex trees, functions, values and promises. Clues consists of a single getter function (just over 100 loc) that dynamically resolves dependency trees and memoizes resolutions (lets call them derived facts) along the way. | ||
#### using first element to define private scope | ||
But what if we want to hide certain parts of the tree from direct traversal, but still be able to use those hidden parts for logic? Array defined functions can be used to form gateways from one tree into a subtree of another. If the first element of an array-defined function is an object or a function, that object provides a separate scope the function will be evaluated in. The function can therefore act as a selector from this private scope. | ||
But what if we want to hide certain parts of the tree from direct traversal, but still be able to use those hidden parts for logic? Array defined functions can be used to form gateways from one tree into a subtree of another. If the first element of an array-defined function is an object (and not an array) or a function, that object provides a separate scope the function will be evaluated in. The function can therefore act as a selector from this private scope. | ||
@@ -385,0 +385,0 @@ Public/private Example: |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
var clues = require('../clues'), | ||
assert = require('assert'), | ||
Promise = require('bluebird'); | ||
@@ -12,2 +12,3 @@ | ||
M4 : function(M3) { return M3;}, | ||
recursive : [['M1',Number],[['M2',Number],['M3',Number],Array],Array], | ||
regular_array : [1,2,3,4], | ||
@@ -63,2 +64,8 @@ nested : [function() { | ||
}); | ||
it('should work recursively',function() { | ||
return clues(facts,'recursive').then(function(d) { | ||
assert.deepEqual(d,[10,[300,310]]); | ||
}); | ||
}); | ||
}); |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
var clues = require('../clues'), | ||
assert = require('assert'), | ||
crypto = require('crypto'); | ||
@@ -24,2 +24,7 @@ | ||
var pub = { | ||
M1 : 100, | ||
M2 : 200 | ||
}; | ||
it('works without array arguments',function() { | ||
@@ -53,2 +58,8 @@ var obj = private(); | ||
}); | ||
it('works recursively',function() { | ||
return clues({},[Object.create(pub),[['M1',Number],['M2',Number],[private(),'forty',Number],Array],function(d) { | ||
assert.deepEqual(d,[100,200,40]); | ||
}]); | ||
}); | ||
}); | ||
@@ -55,0 +66,0 @@ |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"); | ||
var clues = require('../clues'), | ||
assert = require('assert'); | ||
@@ -4,0 +4,0 @@ function obj() { |
@@ -1,4 +0,4 @@ | ||
var clues = require("../clues"), | ||
var clues = require('../clues'), | ||
Promise = require('bluebird'), | ||
assert = require("assert"); | ||
assert = require('assert'); | ||
@@ -5,0 +5,0 @@ describe('cancellation',function() { |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
var clues = require('../clues'), | ||
assert = require('assert'), | ||
Promise = require('bluebird'); | ||
@@ -4,0 +4,0 @@ |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"); | ||
var clues = require('../clues'), | ||
assert = require('assert'); | ||
@@ -4,0 +4,0 @@ function shouldErr() { throw 'Should throw an error'; } |
@@ -1,4 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
Promise = require('bluebird'); | ||
var clues = require('../clues'), | ||
assert = require('assert'); | ||
@@ -5,0 +4,0 @@ describe('$external',function() { |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
var clues = require('../clues'), | ||
assert = require('assert'), | ||
Promise = require('bluebird'); | ||
@@ -4,0 +4,0 @@ |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"); | ||
var clues = require('../clues'), | ||
assert = require('assert'); | ||
@@ -33,3 +33,3 @@ describe('Global variable',function() { | ||
j : function(test) { | ||
return test | ||
return test; | ||
} | ||
@@ -36,0 +36,0 @@ }; |
@@ -1,4 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
Promise = require('bluebird'); | ||
var clues = require('../clues'), | ||
assert = require('assert'); | ||
@@ -5,0 +4,0 @@ function logic($global) { |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
var clues = require('../clues'), | ||
assert = require('assert'), | ||
Promise = require('bluebird'); | ||
@@ -4,0 +4,0 @@ |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
var clues = require('../clues'), | ||
assert = require('assert'), | ||
Promise = require('bluebird'); | ||
@@ -52,3 +52,3 @@ | ||
var logic2 = { | ||
error : function() { throw "#Error"; }, | ||
error : function() { throw '#Error'; }, | ||
optional : function(_error) { return _error; }, | ||
@@ -68,6 +68,6 @@ regular : function(error) { return error; }, | ||
return clues(Object.create(logic2),'regular') | ||
.then(function(d) { | ||
.then(function() { | ||
throw 'Should error'; | ||
},function(e) { | ||
assert.equal(e.message,"#Error"); | ||
assert.equal(e.message,'#Error'); | ||
}); | ||
@@ -74,0 +74,0 @@ }); |
@@ -1,4 +0,3 @@ | ||
var instinct = require("../clues"), | ||
assert = require("assert"), | ||
Promise = require('bluebird'); | ||
var instinct = require('../clues'), | ||
assert = require('assert'); | ||
@@ -5,0 +4,0 @@ describe('$property',function() { |
@@ -1,3 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
var clues = require('../clues'), | ||
assert = require('assert'), | ||
Promise = require('bluebird'); | ||
@@ -4,0 +4,0 @@ |
@@ -1,4 +0,3 @@ | ||
var clues = require("../clues"), | ||
assert = require("assert"), | ||
Promise = require('bluebird'); | ||
var clues = require('../clues'), | ||
assert = require('assert'); | ||
@@ -5,0 +4,0 @@ describe('$ as a first letter',function() { |
@@ -1,4 +0,4 @@ | ||
/* global self*/ | ||
(function() { | ||
(function(self) { | ||
var clues,request; | ||
var reptile = {}; | ||
@@ -14,138 +14,123 @@ if (typeof module !== 'undefined') { | ||
var Promise = clues.prototype.Promise; | ||
var Promise = clues.Promise; | ||
function reptile(logic,facts,options) { | ||
if (!(this instanceof reptile)) | ||
return new reptile(logic,facts,options); | ||
function fetch(queue,input,options) { | ||
if (!(this instanceof fetch)) | ||
return new fetch(queue,input,options); | ||
this.queue = queue; | ||
options = options || {}; | ||
options.fallback = this.external; | ||
this.url = options.url || '/api/'; | ||
this.queue = {}; | ||
this.data = Object.create(facts || {}); | ||
this.fetcher = undefined; | ||
clues.call(this,logic,facts,options); | ||
this.input = input; | ||
this.buffer = ''; | ||
this.options = options || {}; | ||
this.options.delay = this.options.delay || 100; | ||
this.ajaxRequest(); | ||
} | ||
reptile.prototype = Object.create(clues.prototype); | ||
fetch.prototype.ajaxRequest = function() { | ||
var r = new XMLHttpRequest(), | ||
self = this, | ||
last = 0; | ||
reptile.prototype.fetch = function() { | ||
var self = this; | ||
r.open('POST',this.options.url+Object.keys(this.queue),true); | ||
r.setRequestHeader('Content-Type','application/json;charset=UTF-8'); | ||
r.send(JSON.stringify(this.input)); | ||
r.onprogress = function() { | ||
self.processBuffer(r.responseText.slice(last)); | ||
last = r.responseText.length; | ||
}; | ||
r.onload = function() { | ||
self.processBuffer(r.responseText.slice(last)); | ||
}; | ||
}; | ||
self.fetcher = self.fetcher || Promise.delay(self.options.delay) | ||
.then(function() { | ||
return new Promise(function(resolve,reject) { | ||
self.fetcher = undefined; | ||
if (!Object.keys(self.queue).length) return resolve(true); | ||
var queue = self.queue; | ||
self.queue = {}; | ||
var inputs = {}; | ||
fetch.prototype.nodeRequest = function() { | ||
request({ | ||
url : this.options.url+Object.keys(this.queue), | ||
method : 'POST', | ||
json : this.input | ||
}) | ||
.on('data',this.processBuffer.bind(this)) | ||
.on('error',this.requestFailed.bind(this)); | ||
}; | ||
for (var key in self.facts) { | ||
if (self.facts[key] && typeof self.facts[key].then !== 'function') inputs[key] = self.facts[key]; | ||
} | ||
function processBuffer(text) { | ||
buffer += text; | ||
var items = buffer.split(',\t\n'); | ||
if (items.length < 2) return; | ||
fetch.prototype.requestFailed = function(e) { | ||
Object.keys(this.queue) | ||
.forEach(function(key) { | ||
this.queue[key].reject(e); | ||
},this); | ||
}; | ||
buffer = items.slice(items.length-1); | ||
fetch.prototype.processBuffer = function(d) { | ||
if (d) this.buffer += d; | ||
items.slice(0,items.length-1) | ||
.forEach(function(item) { | ||
var m = /\s*\"(.*?)\"\s*\:\s*(.*)/.exec(item); | ||
if (m) { | ||
var key = m[1],value; | ||
try { | ||
value = JSON.parse(m[2]); | ||
} catch(e) { | ||
value = {error:true,message:'JSON parse error: '+e}; | ||
} | ||
if (!queue[key]) return; | ||
self.data[key] = value; | ||
if (value && value.error) | ||
queue[key].reject(value); | ||
else | ||
queue[key].resolve(value); | ||
if (self.options.applyFn) self.options.applyFn(); | ||
} | ||
}); | ||
} | ||
var queue = this.queue; | ||
var items = this.buffer.split(',\t\n'); | ||
this.buffer = items.slice(items.length-1)[0]; | ||
if (typeof module == 'undefined') { | ||
// In browser we use XMLHttpRequest | ||
var r = new XMLHttpRequest(); | ||
var buffer = '',last = 0; | ||
r.open('POST',self.url+Object.keys(queue),true); | ||
r.setRequestHeader('Content-Type','application/json;charset=UTF-8'); | ||
r.send(JSON.stringify(inputs)); | ||
r.onprogress = function() { | ||
processBuffer(r.responseText.slice(last)); | ||
last = r.responseText.length; | ||
}; | ||
r.onload = function() { | ||
processBuffer(r.responseText.slice(last)); | ||
resolve(true); | ||
}; | ||
} else { | ||
// In node.js we use request.js | ||
var options = {}; | ||
if (self.options.request) | ||
Object.keys(self.options.request).forEach(function(key) { | ||
options[key] = self.options.request[key]; | ||
}); | ||
options.url = self.url+Object.keys(queue); | ||
options.method = options.method || 'POST'; | ||
options.json = inputs; | ||
request(options) | ||
.on('data',function(d) { | ||
processBuffer(d); | ||
}) | ||
.on('error',function(e) { | ||
Object.keys(queue) | ||
.forEach(function(d) { | ||
queue[d].reject(e); | ||
}); | ||
resolve(true); | ||
}) | ||
.on('end',function() { | ||
resolve(true); | ||
}); | ||
} | ||
}); | ||
if (items.length < 2) return; | ||
items.slice(0,items.length-1) | ||
.forEach(function(item) { | ||
var m = /\s*\"(.*?)\"\s*\:\s*(.*)/.exec(item); | ||
if (!m) return; | ||
var key = m[1],value; | ||
if (!queue[key]) return; | ||
try { | ||
value = JSON.parse(m[2]); | ||
} catch(e) { | ||
value = {error:true,message:'JSON parse error: '+e}; | ||
} | ||
console.log(key,value) | ||
if (value && value.error) | ||
queue[key].reject(value); | ||
else | ||
queue[key].resolve(value); | ||
}); | ||
return self.fetcher; | ||
}; | ||
reptile.prototype.external = function(ref) { | ||
if (this.facts[ref]) return this.facts[ref]; | ||
var result = this.queue[ref] = this.queue[ref] || Promise.defer(); | ||
this.fetch(); | ||
return result.promise; | ||
}; | ||
function fetcher(options) { | ||
var queue = {}, | ||
next, | ||
inputLock; | ||
options = options || {}; | ||
options.delay = options.delay || 100; | ||
reptile.prototype.fork = function(update,extraOptions) { | ||
update = update || {}; | ||
extraOptions = extraOptions || {}; | ||
var facts = Object.create(this.facts); | ||
Object.keys(update).forEach(function(key) { | ||
facts[key] = update[key]; | ||
}); | ||
var options = Object.create(this.options); | ||
Object.keys(extraOptions).forEach(function(key) { | ||
options[key] = extraOptions[key]; | ||
}); | ||
return reptile(this.logic,facts,options); | ||
}; | ||
return function(ref) { | ||
return function(input) { | ||
reptile.prototype.refresh = function(inputs,clearData) { | ||
this.facts = inputs || {}; | ||
if (clearData) this.data = Object.create(inputs); | ||
return this; | ||
// Ensure that input object is consistent | ||
if (inputLock && input !== inputLock) { | ||
queue = {}; | ||
return Promise.rejected('INCONSISTENT_INPUT'); | ||
} | ||
inputLock = input; | ||
// Fire off the fetch after an optional delay | ||
if (!next) next = Promise.delay(options.delay) | ||
.then(function() { | ||
fetch(queue,input,options); | ||
queue={}; | ||
input={}; | ||
next = undefined; | ||
inputLock=undefined; | ||
}); | ||
return (queue[ref] = Promise.defer()).promise; | ||
}; | ||
}; | ||
} | ||
reptile.fetcher = fetcher; | ||
reptile.fetch = fetch; | ||
reptile.$external = function(options) { | ||
return { | ||
$external : reptile.fetcher(options) | ||
}; | ||
}; | ||
reptile.prototype.render = function(element) { | ||
reptile.render = function(obj,widgets,element) { | ||
var self = this; | ||
@@ -156,10 +141,7 @@ var keys = element.dataset.reptile.split(','),key; | ||
key = keys.shift(); | ||
return Promise.try(function() { | ||
if (!key || !self.logic[key]) throw {message:'Not defined',ref:key}; | ||
return self.solve(self.logic[key],{element:element}); | ||
}) | ||
.catch(function(e) { | ||
if (keys.length) return renderKey(); | ||
element.innerHTML = 'Error: '+e.message+' ('+e.ref+')'; | ||
}); | ||
return clues(obj,widgets[key],{element:element}) | ||
.catch(function(e) { | ||
if (keys.length) return renderKey(); | ||
element.innerHTML = 'Error: '+e.message+' ('+e.ref+')'; | ||
}); | ||
} | ||
@@ -169,3 +151,3 @@ return renderKey(); | ||
reptile.prototype.renderAll = function(element) { | ||
reptile.renderAll = function(element) { | ||
var self = this; | ||
@@ -180,2 +162,2 @@ if (!element && !window) throw 'Not in a browser - element must be provided'; | ||
})(); | ||
})(this); |
@@ -5,10 +5,13 @@ var clues = require('../clues'), | ||
function jsonReplacer(key, value) { | ||
if (value && typeof value === 'object') { | ||
if (!value || value instanceof Date) return value; | ||
if (typeof value === 'function' || value.length && typeof value[value.length-1] === 'function') | ||
return '[Function]'; | ||
if (typeof value.then === 'function') | ||
return '[Promise]'; | ||
if (typeof value === 'object' ) { | ||
var tmp = Array.isArray(value) ? [] : {}; | ||
for (key in value) | ||
tmp[key] = value[key]; | ||
tmp[key] = jsonReplacer(key,value[key]); | ||
value = tmp; | ||
} | ||
if (typeof value === 'function' || (value && value.length && typeof value[value.length-1] === 'function')) | ||
return '[Function]'; | ||
return value; | ||
@@ -75,2 +78,3 @@ } | ||
if (d === undefined) d = null; | ||
for (var key in d) d[key] = d[key]; | ||
var txt = {}; | ||
@@ -77,0 +81,0 @@ txt[ref] = d; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
78231
27
1626
34