Skip to content
This repository was archived by the owner on Feb 4, 2025. It is now read-only.

Commit e68d842

Browse files
committed
refactore: start applying visitors
1 parent 90da723 commit e68d842

File tree

12 files changed

+124
-177
lines changed

12 files changed

+124
-177
lines changed

src/createJsonLogic.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,96 @@
1+
import isLogic from './isLogic';
2+
import getOperator from './getOperator';
3+
14
function createJsonLogic() {
5+
const operations = {}
6+
const visitors = {}
7+
8+
function addOperation(name, code) {
9+
operations[name] = code;
10+
}
11+
12+
function removeOperation(name) {
13+
delete operations[name];
14+
}
15+
16+
function addVisitor(name, code) {
17+
if (Array.isArray(name)) {
18+
name.forEach(addVisitor);
19+
}
20+
21+
visitors[name] = code;
22+
}
23+
24+
function removeVisitor(name) {
25+
if (Array.isArray(name)) {
26+
name.forEach(removeVisitor);
27+
}
28+
29+
delete visitors[name];
30+
}
31+
32+
function apply(logic, data) {
33+
// Does this array contain logic? Only one way to find out.
34+
if(Array.isArray(logic)) {
35+
return logic.map(function(l) {
36+
return apply(l, data);
37+
});
38+
}
39+
// You've recursed to a primitive, stop!
40+
if( ! isLogic(logic) ) {
41+
return logic;
42+
}
43+
44+
data = data || {};
45+
46+
const op = getOperator(logic);
47+
let values = logic[op];
48+
let i;
49+
50+
// easy syntax for unary operators, like {"var" : "x"} instead of strict {"var" : ["x"]}
51+
if( ! Array.isArray(values)) {
52+
values = [values];
53+
}
54+
55+
// apply matching visitors first
56+
if (typeof visitors[op] === 'function') {
57+
return visitors[op](apply, data, values);
58+
}
59+
60+
// Everyone else gets immediate depth-first recursion
61+
values = values.map(function(val) {
62+
return apply(val, data);
63+
});
64+
65+
// The operation is called with "data" bound to its "this" and "values" passed as arguments.
66+
// Structured commands like % or > can name formal arguments while flexible commands (like missing or merge) can operate on the pseudo-array arguments
67+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
68+
if(typeof operations[op] === "function") {
69+
return operations[op].apply(data, values);
70+
}else if(op.indexOf(".") > 0) { // Contains a dot, and not in the 0th position
71+
var sub_ops = String(op).split(".");
72+
var operation = operations;
73+
for(i = 0; i < sub_ops.length; i++) {
74+
// Descending into operations
75+
operation = operation[sub_ops[i]];
76+
if(operation === undefined) {
77+
throw new Error("Unrecognized operation " + op +
78+
" (failed at " + sub_ops.slice(0, i+1).join(".") + ")");
79+
}
80+
}
81+
82+
return operation.apply(data, values);
83+
}
84+
85+
throw new Error("Unrecognized operation " + op );
86+
}
287

88+
return {
89+
add_operation: addOperation,
90+
rm_operation: removeOperation,
91+
add_visitor: addVisitor,
92+
rm_visitor: removeVisitor,
93+
}
394
}
495

596
export default createJsonLogic;

src/helpers/apply.js

Lines changed: 0 additions & 167 deletions
This file was deleted.

src/index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import createJsonLogic from './createJsonLogic';
2+
import * as operations from './operations';
3+
import * as visitors from './visitors';
4+
5+
const jsonLogic = createJsonLogic();
6+
7+
Object.keys(operations).forEach(function(name) {
8+
const operation = operations[name];
9+
10+
jsonLogic.add_operation(operation.code || name , operation);
11+
});
12+
13+
Object.keys(visitors).forEach(function(name) {
14+
const visitor = visitors[name];
15+
16+
jsonLogic.add_visitor(visitor.code || name , visitor);
17+
});
18+
19+
export default jsonLogic;

src/visitors/all.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import truthy from "../helpers/truthy";
22

3-
function all(data, values) {
3+
function all(apply, data, values) {
44
const scopedData = apply(values[0], data);
55
const scopedLogic = values[1];
66
// All of an empty set is false. Note, some and none have correct fallback after the for loop

src/visitors/and.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import truthy from "../helpers/truthy";
22

3-
function and(data, values, current) {
3+
function and(apply, data, values) {
4+
let current;
5+
46
for(let i=0; i < values.length; i++) {
57
current = apply(values[i], data);
68
if( ! truthy(current)) {

src/visitors/condition.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import truthy from '../helpers/truthy';
22

3-
function condition(data, values) {
3+
function condition(apply, data, values) {
44
/* 'if' should be called with a odd number of parameters, 3 or greater
55
This works on the pattern:
66
if( 0 ){ 1 }else{ 2 };
@@ -27,6 +27,6 @@ function condition(data, values) {
2727
return null;
2828
}
2929

30-
condition.code = 'if';
30+
condition.code = ['if', '?:'];
3131

3232
export default condition;

src/visitors/filter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import truthy from "../helpers/truthy";
22

3-
function filter(data, values) {
3+
function filter(apply, data, values) {
44
const scopedData = apply(values[0], data);
55
const scopedLogic = values[1];
66

src/visitors/map.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function map(data, values) {
1+
function map(apply, data, values) {
22
const scopedData = apply(values[0], data);
33
const scopedLogic = values[1];
44

src/visitors/none.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function none(data, values) {
1+
function none(apply, data, values) {
22
const filtered = apply({'filter' : values}, data);
33

44
return filtered.length === 0;

src/visitors/or.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import truthy from "../helpers/truthy";
22

3-
function or(data, values, current) {
3+
function or(apply, data, values) {
4+
let current;
5+
46
for(let i=0; i < values.length; i++) {
57
current = apply(values[i], data);
68
if( truthy(current) ) {

0 commit comments

Comments
 (0)