Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ env:
extends: 'eslint:recommended'
globals:
Promise: false
parserOptions:
ecmaVersion: 6
rules:
indent: [ 2, 2, { SwitchCase: 1 } ]
no-trailing-spaces: 2
Expand Down
4 changes: 3 additions & 1 deletion lib/jsonscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ function addAjvKeywords() {
addAjvKeyword.call(this, 'validateAsync');
addAjvKeyword.call(this, 'itemsSerial', 'array');
this._evalKeywords.objectToAsync = util.objectToPromise;
this._evalKeywords.valueToAsync = util.toPromise;
addAjvKeyword.call(this, 'objectToAsync', 'object', true);
addAjvKeyword.call(this, 'valueToAsync', undefined, true);
this.ajv.addKeyword('resolvePendingRefs', {
validate: evaluationKeywords.resolvePendingRefs,
schema: false
Expand Down Expand Up @@ -151,7 +153,7 @@ function addCoreInstructions() {
* @this JSONScript
*/
function generateSchemas() {
this.ajv.addMetaSchema(_generate.call(this, 'evaluate_metaschema'));
// this.ajv.addMetaSchema(_generate.call(this, 'evaluate_metaschema'));
this._validate = this.ajv.compile(_generate.call(this, 'schema'));
this._evaluate = this.ajv.compile(_generate.call(this, 'evaluate'));
// console.log(this._validate.toString().length, this._evaluate.toString().length);
Expand Down
75 changes: 33 additions & 42 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ module.exports = {
copy: copy,
objectToPromise: objectToPromise,
promiseMapSerial: promiseMapSerial,
isPromise: isPromise,
toPromise: toPromise,
toAbsolutePointer: toAbsolutePointer
};

Expand All @@ -20,65 +22,54 @@ function copy(o, to) {


function objectToPromise(obj) {
var isPromise, promises, key;
for (key in obj) {
var promises = [];
var results = {};
for (var key in obj) {
var value = obj[key];
if (value && typeof value.then == 'function')
if (isPromise(value)) {
results[key] = undefined;
defer(value, key);
} else {
results[key] = value;
}
}
if (!promises) return obj;
var results = {};
for (key in obj)
results[key] = isPromise[key] ? undefined : obj[key];

if (promises.length == 1) return promises[0];
return Promise.all(promises).then(function() { return results; });
return promises.length
? Promise.all(promises).then(() => results)
: Promise.resolve(obj);

function defer(p, _key) {
isPromise = isPromise || {};
isPromise[_key] = true;
p = p.then(function (res) {
results[_key] = res;
return results;
});
if (!promises) promises = [p];
else promises.push(p);
p = p.then((res) => { results[_key] = res; });
promises.push(p);
}
}


function promiseMapSerial(arr, func, thisArg) {
var results = Array(arr.length);
var start = 0;
var pos = 0;
return map();

function map() {
for (var i=start; i<arr.length; i++) {
var item = arr[i];
if (item && typeof item.then == 'function') {
return item.then(function (itemRes) {
var value = func.call(thisArg, itemRes, i);
return value && typeof value.then == 'function'
? value.then(mapRest(i))
: mapRest(i)(value);
});
}

var value = func.call(thisArg, item, i);
if (value && typeof value.then == 'function')
return value.then(mapRest(i));
results[i] = value;
}
return results;
var item = toPromise(arr[pos]);
return item.then(function (itemRes) {
return func.call(thisArg, itemRes, pos);
})
.then(function (value) {
results[pos++] = value;
return pos == arr.length ? results : map();
});
}
}

function mapRest(i) {
return function (res) {
results[i] = res;
start = i+1;
return start == arr.length ? results : map();
};
}

function isPromise(value) {
return value && typeof value.then == 'function';
}


function toPromise(value) {
return isPromise(value) ? value : Promise.resolve(value);
}


Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jsonscript-js",
"version": "0.1.3",
"version": "0.2.0",
"description": "JavaScript interpreter for JSONScript",
"main": "lib/jsonscript.js",
"scripts": {
Expand Down Expand Up @@ -30,14 +30,14 @@
"ajv": "^3.7.1",
"dot": "^1.0.3",
"json-pointer": "^0.3.1",
"jsonscript": "^0.1.3"
"jsonscript": "^0.2.0"
},
"devDependencies": {
"coveralls": "^2.11.6",
"eslint": "^2.2.0",
"istanbul": "^0.4.2",
"jsonscript-test": "^0.1.1",
"jsonscript-test-suite": "^0.1.1",
"jsonscript-test": "^0.2.0",
"jsonscript-test-suite": "^0.1.3",
"mocha": "^2.4.5",
"pre-commit": "^1.1.2"
}
Expand Down
2 changes: 1 addition & 1 deletion spec/$delay.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('$delay instruction - delayed evaluation', function() {
callsResolutions = getPromise.callsResolutions = [];
});

it('should delay $wait milliseconds', function (){
it.skip('should delay $wait milliseconds', function (){
var result;

var script = {
Expand Down
7 changes: 4 additions & 3 deletions spec/evaluation_keywords.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,14 @@ describe('evaluation keywords', function() {
validate = js.ajv.compile(schema);
});

it('should leave object as is if there are no promises', function() {
it('should return promise resolving to object if there are no promises', function() {
var obj = { a: 1, b: 2, c: 3 };
var data = { obj: obj };
assert(validate.call({ js: js }, data));
assert.strictEqual(validate.errors, null);
assert.equal(data.obj, obj);
assert.deepEqual(data.obj, obj);
return data.obj.then(function (o) {
assert.deepEqual(o, obj);
});
});

it('should merge promises in properties in a single promise', function() {
Expand Down
15 changes: 9 additions & 6 deletions spec/util.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ describe('util', function() {
describe('objectToPromise', function() {
var objectToPromise = util.objectToPromise;

it('should return the same object if there are no promises', function() {
it('should return promise if there are no promises', function() {
var obj = { a: 1, b: 2 };
var result = objectToPromise(obj);
assert.deepEqual(result, obj);
assert.equal(result, obj);
return result.then(function (res) {
assert.deepEqual(res, obj);
});
});

it('should return promise resolving to object without promises (if object has one promise)', function() {
Expand Down Expand Up @@ -59,9 +60,11 @@ describe('util', function() {

it('should map array without promises synchronously', function() {
var arr = [1, 2, 3];
var result = promiseMapSerial(arr, syncMapper);
assert.deepEqual(result, [10, 20, 30]);
assert.deepEqual(callsResolutions, [{ call: 1 }, { call: 2 }, { call: 3 }]);
return promiseMapSerial(arr, syncMapper)
.then(function (result) {
assert.deepEqual(result, [10, 20, 30]);
assert.deepEqual(callsResolutions, [{ call: 1 }, { call: 2 }, { call: 3 }]);
});
});

it('should return promise resolving to array without promises (if array has one promise)', function() {
Expand Down