Skip to content

Commit 5f37b91

Browse files
committed
predefined executors array and calc
1 parent 3ed3560 commit 5f37b91

6 files changed

Lines changed: 297 additions & 5 deletions

File tree

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
JavaScript interpreter for [JSONScript](https://github.com/JSONScript/jsonscript)
44

5-
It is work in progress.
6-
75
[![Build Status](https://travis-ci.org/JSONScript/jsonscript-js.svg?branch=master)](https://travis-ci.org/JSONScript/jsonscript-js)
86
[![npm version](https://badge.fury.io/js/jsonscript-js.svg)](https://www.npmjs.com/package/jsonscript-js)
97
[![Code Climate](https://codeclimate.com/github/JSONScript/jsonscript-js/badges/gpa.svg)](https://codeclimate.com/github/JSONScript/jsonscript-js)

lib/executors/array.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
4+
module.exports = {
5+
map: arrayMap,
6+
every: arrayEvery,
7+
some: arraySome,
8+
filter: arrayFilter
9+
};
10+
11+
12+
function arrayMap(args) {
13+
var result = Array.isArray(args)
14+
? args[0].map(args[1])
15+
: args.data.map(args.iterator);
16+
return Promise.all(result);
17+
}
18+
19+
20+
function arrayEvery(args) {
21+
var result = Array.isArray(args)
22+
? args[0].map(args[1])
23+
: args.data.map(args.iterator);
24+
return Promise.all(result).then(function (items) {
25+
return items.every(function (item) {
26+
return item === true;
27+
});
28+
});
29+
}
30+
31+
32+
function arraySome(args) {
33+
var result = Array.isArray(args)
34+
? args[0].map(args[1])
35+
: args.data.map(args.iterator);
36+
return Promise.all(result).then(function (items) {
37+
return items.some(function (item) {
38+
return item === true;
39+
});
40+
});
41+
}
42+
43+
44+
function arrayFilter(args) {
45+
var data, iterator;
46+
if (Array.isArray(args)) {
47+
data = args[0];
48+
iterator = args[1];
49+
} else {
50+
data = args.data;
51+
iterator = args.iterator;
52+
}
53+
var result = data.map(iterator);
54+
return Promise.all(result).then(function (items) {
55+
return data.filter(function (val, i) {
56+
return items[i] === true;
57+
});
58+
});
59+
}

lib/executors/calc.js

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
'use strict';
2+
3+
4+
module.exports = {
5+
add: calcAdd,
6+
subtract: calcSubtract,
7+
multiply: calcMultiply,
8+
divide: calcDivide,
9+
equal: calcEqual,
10+
notEqual: calcNotEqual,
11+
greater: calcGreater,
12+
lesser: calcLesser,
13+
greaterEqual: calcGreaterEqual,
14+
lesserEqual: calcLesserEqual,
15+
and: calcAnd,
16+
or: calcOr,
17+
not: calcNot,
18+
xor: calcXor
19+
};
20+
21+
22+
function calcAdd(args) {
23+
var result = 0;
24+
for (var i=0; i<args.length; i++) {
25+
var num = args[i];
26+
if (typeof num != 'number')
27+
throw new Error('add expects numbers');
28+
result += num;
29+
}
30+
return result;
31+
}
32+
33+
34+
function calcSubtract(args) {
35+
var result = args[0];
36+
for (var i=1; i<args.length; i++) {
37+
var num = args[i];
38+
if (typeof num != 'number')
39+
throw new Error('subtract expects numbers');
40+
result -= num;
41+
}
42+
return result;
43+
}
44+
45+
46+
function calcMultiply(args) {
47+
var result = 1;
48+
for (var i=0; i<args.length; i++) {
49+
var num = args[i];
50+
if (typeof num != 'number')
51+
throw new Error('multiply expects numbers');
52+
if (num == 0) return 0;
53+
result *= num;
54+
}
55+
return result;
56+
}
57+
58+
59+
function calcDivide(args) {
60+
var result = args[0];
61+
for (var i=1; i<args.length; i++) {
62+
var num = args[i];
63+
if (typeof num != 'number')
64+
throw new Error('divide expects numbers');
65+
if (num == 0)
66+
throw new Error('division by 0');
67+
result /= num;
68+
}
69+
return result;
70+
}
71+
72+
73+
function calcEqual(args) {
74+
return compareArgs(args, true);
75+
}
76+
77+
78+
function calcNotEqual(args) {
79+
return compareArgs(args, false);
80+
}
81+
82+
83+
function compareArgs(args, shouldBeEqual) {
84+
var item = args[0];
85+
for (var i=1; i<args.length; i++) {
86+
if (args[i] !== item) return !shouldBeEqual;
87+
}
88+
return shouldBeEqual;
89+
}
90+
91+
92+
function calcGreater(args) {
93+
var prev = args[0];
94+
for (var i=1; i<args.length; i++) {
95+
var num = args[i];
96+
if (typeof num != 'number')
97+
throw new Error('greater expects numbers');
98+
if (prev <= num) return false;
99+
prev = num;
100+
}
101+
return true;
102+
}
103+
104+
105+
function calcLesser(args) {
106+
var prev = args[0];
107+
for (var i=1; i<args.length; i++) {
108+
var num = args[i];
109+
if (typeof num != 'number')
110+
throw new Error('greater expects numbers');
111+
if (prev >= num) return false;
112+
prev = num;
113+
}
114+
return true;
115+
}
116+
117+
118+
function calcGreaterEqual(args) {
119+
var prev = args[0];
120+
for (var i=1; i<args.length; i++) {
121+
var num = args[i];
122+
if (typeof num != 'number')
123+
throw new Error('greater expects numbers');
124+
if (prev < num) return false;
125+
prev = num;
126+
}
127+
return true;
128+
}
129+
130+
131+
function calcLesserEqual(args) {
132+
var prev = args[0];
133+
for (var i=1; i<args.length; i++) {
134+
var num = args[i];
135+
if (typeof num != 'number')
136+
throw new Error('greater expects numbers');
137+
if (prev > num) return false;
138+
prev = num;
139+
}
140+
return true;
141+
}
142+
143+
144+
function calcAnd(args) {
145+
for (var i=0; i<args.length; i++) {
146+
var item = args[i];
147+
if (typeof item != 'boolean')
148+
throw new Error('and expects booleans');
149+
if (!item) return false;
150+
}
151+
return true;
152+
}
153+
154+
155+
function calcOr(args) {
156+
for (var i=0; i<args.length; i++) {
157+
var item = args[i];
158+
if (typeof item != 'boolean')
159+
throw new Error('or expects booleans');
160+
if (item) return true;
161+
}
162+
return false;
163+
}
164+
165+
166+
function calcXor(args) {
167+
var result = false;
168+
for (var i=0; i<args.length; i++) {
169+
var item = args[i];
170+
if (typeof item != 'boolean')
171+
throw new Error('or expects booleans');
172+
if (item) {
173+
if (result) return false
174+
result = true;
175+
}
176+
}
177+
return result;
178+
}
179+
180+
181+
function calcNot(args) {
182+
if (typeof args != 'boolean')
183+
throw new Error('not expects boolean');
184+
return !args;
185+
}

lib/executors/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
'use strict';
2+
3+
module.exports = {
4+
array: require('./array'),
5+
calc: require('./calc')
6+
};

lib/instruction_keywords.js

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ module.exports = {
99
eval$ref: eval$ref,
1010
eval$data: eval$data,
1111
eval$if: eval$if,
12-
eval$delay: eval$delay
12+
eval$delay: eval$delay,
13+
eval$func: eval$func
1314
};
1415

1516

@@ -27,11 +28,11 @@ function eval$exec(params) {
2728
if ($method) {
2829
if (typeof executor[$method] != 'function')
2930
throw new Error('unknown method ' + $method + ' of executor ' + $exec);
30-
return executor[$method](params.$args);
31+
return util.toPromise(executor[$method](params.$args));
3132
}
3233
if (typeof executor != 'function')
3334
throw new Error('executor ' + $exec + ' is not a function');
34-
return executor(params.$args);
35+
return util.toPromise(executor(params.$args));
3536
}
3637

3738

@@ -136,6 +137,37 @@ function eval$delay(params) {
136137
}
137138

138139

140+
/**
141+
* Function definition
142+
* @this Evaluation
143+
* @param {Object} params instruction keywords ($func, $name, $args)
144+
* @return {Function} Function that returns Script or synchronous/asynchronous value
145+
*/
146+
function eval$func(params) {
147+
var self = this;
148+
var valid = this.js.validate(params.$func);
149+
if (valid) return Promise.resolve(func);
150+
var err = this.js.ajv.ValidationError(this.js.validate.errors);
151+
return Promise.reject(err);
152+
153+
function func() {
154+
var data = params.$args ? prepareArguments(arguments) : self.data;
155+
var script = JSON.parse(JSON.stringify(params.$func));
156+
return self.js.evaluate(script, data);
157+
}
158+
159+
function prepareArguments(args) {
160+
var data = {};
161+
for (var i=0; i<args.length; i++) {
162+
data[i] = args[i];
163+
var argName = params.$args[i];
164+
if (argName) data[argName] = args[i];
165+
}
166+
return data;
167+
}
168+
}
169+
170+
139171
function isScript(value) {
140172
return value && typeof value == 'object';
141173
}

lib/jsonscript.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var generateSchema = require('./generate_schema');
77
var instructions = require('jsonscript/instructions');
88
var evaluationKeywords = require('./evaluation_keywords');
99
var instructionKeywords = require('./instruction_keywords');
10+
var executors = require('./executors');
1011

1112
module.exports = JSONScript;
1213

@@ -23,6 +24,7 @@ function JSONScript(opts) {
2324

2425
addAjvKeywords.call(this);
2526
addCoreInstructions.call(this);
27+
addExecutors.call(this);
2628
}
2729

2830

@@ -148,6 +150,16 @@ function addCoreInstructions() {
148150
}
149151

150152

153+
/**
154+
* private function to add pre-defined executors
155+
* @this JSONScript
156+
*/
157+
function addExecutors() {
158+
for (var name in executors)
159+
this.addExecutor(name, executors[name]);
160+
}
161+
162+
151163
/**
152164
* private function to regenerate validation and evaluation schemas, called when an instruction is added
153165
* @this JSONScript

0 commit comments

Comments
 (0)