diff --git a/logic.js b/logic.js index e157528..54dadc1 100644 --- a/logic.js +++ b/logic.js @@ -75,14 +75,14 @@ http://ricostacruz.com/cheatsheets/umdjs.html console.log(a); return a; }, "in": function(a, b) { - if(!b || typeof b.indexOf === "undefined") return false; + if (!b || typeof b.indexOf === "undefined") return false; return (b.indexOf(a) !== -1); }, "cat": function() { return Array.prototype.join.call(arguments, ""); }, - "substr":function(source, start, end) { - if(end < 0){ + "substr": function(source, start, end) { + if (end < 0) { // JavaScript doesn't support negative end, this emulates PHP behavior var temp = String(source).substr(start); return temp.substr(0, temp.length + end); @@ -100,9 +100,9 @@ http://ricostacruz.com/cheatsheets/umdjs.html }); }, "-": function(a, b) { - if(b === undefined) { + if (b === undefined) { return -a; - }else{ + } else { return a - b; } }, @@ -123,17 +123,17 @@ http://ricostacruz.com/cheatsheets/umdjs.html "var": function(a, b) { var not_found = (b === undefined) ? null : b; var data = this; - if(typeof a === "undefined" || a==="" || a===null) { + if (typeof a === "undefined" || a==="" || a===null) { return data; } var sub_props = String(a).split("."); - for(var i = 0; i < sub_props.length; i++) { - if(data === null || data === undefined) { + for (var i = 0; i < sub_props.length; i++) { + if (data === null || data === undefined) { return not_found; } // Descending into data data = data[sub_props[i]]; - if(data === undefined) { + if (data === undefined) { return not_found; } } @@ -150,10 +150,10 @@ http://ricostacruz.com/cheatsheets/umdjs.html var missing = []; var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments; - for(var i = 0; i < keys.length; i++) { + for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = jsonLogic.apply({"var": key}, this); - if(value === null || value === "") { + if (value === null || value === "") { missing.push(key); } } @@ -164,9 +164,9 @@ http://ricostacruz.com/cheatsheets/umdjs.html // missing_some takes two arguments, how many (minimum) items must be present, and an array of keys (just like 'missing') to check for presence. var are_missing = jsonLogic.apply({"missing": options}, this); - if(options.length - are_missing.length >= need_count) { + if (options.length - are_missing.length >= need_count) { return []; - }else{ + } else { return are_missing; } }, @@ -187,7 +187,7 @@ http://ricostacruz.com/cheatsheets/umdjs.html Spec and rationale here: http://jsonlogic.com/truthy */ jsonLogic.truthy = function(value) { - if(Array.isArray(value) && value.length === 0) { + if (Array.isArray(value) && value.length === 0) { return false; } return !! value; @@ -204,13 +204,13 @@ http://ricostacruz.com/cheatsheets/umdjs.html jsonLogic.apply = function(logic, data) { // Does this array contain logic? Only one way to find out. - if(Array.isArray(logic)) { + if (Array.isArray(logic)) { return logic.map(function(l) { return jsonLogic.apply(l, data); }); } // You've recursed to a primitive, stop! - if( ! jsonLogic.is_logic(logic) ) { + if ( ! jsonLogic.is_logic(logic) ) { return logic; } @@ -218,15 +218,18 @@ http://ricostacruz.com/cheatsheets/umdjs.html var values = logic[op]; var i; var current; - var scopedLogic, scopedData, filtered, initial; + var scopedLogic; + var scopedData; + var filtered; + var initial; // easy syntax for unary operators, like {"var" : "x"} instead of strict {"var" : ["x"]} - if( ! Array.isArray(values)) { + if ( ! Array.isArray(values)) { values = [values]; } // 'if', 'and', and 'or' violate the normal rule of depth-first calculating consequents, let each manage recursion as needed. - if(op === "if" || op == "?:") { + if (op === "if" || op == "?:") { /* 'if' should be called with a odd number of parameters, 3 or greater This works on the pattern: if( 0 ){ 1 }else{ 2 }; @@ -240,96 +243,91 @@ http://ricostacruz.com/cheatsheets/umdjs.html given one parameter, evaluate and return it. (it's an Else and all the If/ElseIf were false) given 0 parameters, return NULL (not great practice, but there was no Else) */ - for(i = 0; i < values.length - 1; i += 2) { - if( jsonLogic.truthy( jsonLogic.apply(values[i], data) ) ) { + for (i = 0; i < values.length - 1; i += 2) { + if ( jsonLogic.truthy( jsonLogic.apply(values[i], data) ) ) { return jsonLogic.apply(values[i+1], data); } } - if(values.length === i+1) return jsonLogic.apply(values[i], data); + if (values.length === i+1) { + return jsonLogic.apply(values[i], data); + } return null; - }else if(op === "and") { // Return first falsy, or last - for(i=0; i < values.length; i+=1) { + } else if (op === "and") { // Return first falsy, or last + for (i=0; i < values.length; i+=1) { current = jsonLogic.apply(values[i], data); - if( ! jsonLogic.truthy(current)) { + if ( ! jsonLogic.truthy(current)) { return current; } } return current; // Last - }else if(op === "or") {// Return first truthy, or last - for(i=0; i < values.length; i+=1) { + } else if (op === "or") {// Return first truthy, or last + for (i=0; i < values.length; i+=1) { current = jsonLogic.apply(values[i], data); - if( jsonLogic.truthy(current) ) { + if ( jsonLogic.truthy(current) ) { return current; } } return current; // Last - - - - - }else if(op === 'filter'){ + } else if (op === "filter") { scopedData = jsonLogic.apply(values[0], data); scopedLogic = values[1]; if ( ! Array.isArray(scopedData)) { - return []; + return []; } // Return only the elements from the array in the first argument, // that return truthy when passed to the logic in the second argument. // For parity with JavaScript, reindex the returned array - return scopedData.filter(function(datum){ - return jsonLogic.truthy( jsonLogic.apply(scopedLogic, datum)); + return scopedData.filter(function(datum) { + return jsonLogic.truthy( jsonLogic.apply(scopedLogic, datum)); }); - }else if(op === 'map'){ + } else if (op === "map") { scopedData = jsonLogic.apply(values[0], data); scopedLogic = values[1]; if ( ! Array.isArray(scopedData)) { - return []; + return []; } - return scopedData.map(function(datum){ - return jsonLogic.apply(scopedLogic, datum); + return scopedData.map(function(datum) { + return jsonLogic.apply(scopedLogic, datum); }); - - }else if(op === 'reduce'){ + } else if (op === "reduce") { scopedData = jsonLogic.apply(values[0], data); scopedLogic = values[1]; - initial = typeof values[2] !== 'undefined' ? values[2] : null; + initial = typeof values[2] !== "undefined" ? values[2] : null; if ( ! Array.isArray(scopedData)) { - return initial; + return initial; } return scopedData.reduce( - function(accumulator, current){ - return jsonLogic.apply( - scopedLogic, - {'current':current, 'accumulator':accumulator} - ); - }, - initial + function(accumulator, current) { + return jsonLogic.apply( + scopedLogic, + {current: current, accumulator: accumulator} + ); + }, + initial ); - - }else if(op === "all") { + } else if (op === "all") { scopedData = jsonLogic.apply(values[0], data); scopedLogic = values[1]; // All of an empty set is false. Note, some and none have correct fallback after the for loop - if( ! scopedData.length) { + if ( ! scopedData.length) { return false; } - for(i=0; i < scopedData.length; i+=1) { - if( ! jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) { + for (i=0; i < scopedData.length; i+=1) { + if ( ! jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) { return false; // First falsy, short circuit } } return true; // All were truthy - }else if(op === "none") { - filtered = jsonLogic.apply({'filter' : values}, data); + } else if (op === "none") { + filtered = jsonLogic.apply({filter: values}, data); return filtered.length === 0; - - }else if(op === "some") { - filtered = jsonLogic.apply({'filter' : values}, data); + } else if (op === "some") { + filtered = jsonLogic.apply({filter: values}, data); return filtered.length > 0; } @@ -342,17 +340,17 @@ http://ricostacruz.com/cheatsheets/umdjs.html // The operation is called with "data" bound to its "this" and "values" passed as arguments. // Structured commands like % or > can name formal arguments while flexible commands (like missing or merge) can operate on the pseudo-array arguments // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments - if(typeof operations[op] === "function") { + if (typeof operations[op] === "function") { return operations[op].apply(data, values); - }else if(op.indexOf(".") > 0) { // Contains a dot, and not in the 0th position + } else if (op.indexOf(".") > 0) { // Contains a dot, and not in the 0th position var sub_ops = String(op).split("."); var operation = operations; - for(i = 0; i < sub_ops.length; i++) { + for (i = 0; i < sub_ops.length; i++) { // Descending into operations operation = operation[sub_ops[i]]; - if(operation === undefined) { + if (operation === undefined) { throw new Error("Unrecognized operation " + op + - " (failed at " + sub_ops.slice(0, i+1).join(".") + ")"); + " (failed at " + sub_ops.slice(0, i+1).join(".") + ")"); } } @@ -365,18 +363,18 @@ http://ricostacruz.com/cheatsheets/umdjs.html jsonLogic.uses_data = function(logic) { var collection = []; - if( jsonLogic.is_logic(logic) ) { + if (jsonLogic.is_logic(logic)) { var op = jsonLogic.get_operator(logic); var values = logic[op]; - if( ! Array.isArray(values)) { + if ( ! Array.isArray(values)) { values = [values]; } - if(op === "var") { + if (op === "var") { // This doesn't cover the case where the arg to var is itself a rule. collection.push(values[0]); - }else{ + } else { // Recursion! values.map(function(val) { collection.push.apply(collection, jsonLogic.uses_data(val) ); @@ -397,30 +395,30 @@ http://ricostacruz.com/cheatsheets/umdjs.html jsonLogic.rule_like = function(rule, pattern) { // console.log("Is ". JSON.stringify(rule) . " like " . JSON.stringify(pattern) . "?"); - if(pattern === rule) { + if (pattern === rule) { return true; } // TODO : Deep object equivalency? - if(pattern === "@") { + if (pattern === "@") { return true; } // Wildcard! - if(pattern === "number") { + if (pattern === "number") { return (typeof rule === "number"); } - if(pattern === "string") { + if (pattern === "string") { return (typeof rule === "string"); } - if(pattern === "array") { + if (pattern === "array") { // !logic test might be superfluous in JavaScript return Array.isArray(rule) && ! jsonLogic.is_logic(rule); } - if(jsonLogic.is_logic(pattern)) { - if(jsonLogic.is_logic(rule)) { + if (jsonLogic.is_logic(pattern)) { + if (jsonLogic.is_logic(rule)) { var pattern_op = jsonLogic.get_operator(pattern); var rule_op = jsonLogic.get_operator(rule); - if(pattern_op === "@" || pattern_op === rule_op) { - // echo "\nOperators match, go deeper\n"; + if (pattern_op === "@" || pattern_op === rule_op) { + // echo "\nOperators match, go deeper\n"; return jsonLogic.rule_like( jsonLogic.get_values(rule, false), jsonLogic.get_values(pattern, false) @@ -430,22 +428,22 @@ http://ricostacruz.com/cheatsheets/umdjs.html return false; // pattern is logic, rule isn't, can't be eq } - if(Array.isArray(pattern)) { - if(Array.isArray(rule)) { - if(pattern.length !== rule.length) { + if (Array.isArray(pattern)) { + if (Array.isArray(rule)) { + if (pattern.length !== rule.length) { return false; } /* Note, array order MATTERS, because we're using this array test logic to consider arguments, where order can matter. (e.g., + is commutative, but '-' or 'if' or 'var' are NOT) */ - for(var i = 0; i < pattern.length; i += 1) { + for (var i = 0; i < pattern.length; i += 1) { // If any fail, we fail - if( ! jsonLogic.rule_like(rule[i], pattern[i])) { + if ( ! jsonLogic.rule_like(rule[i], pattern[i])) { return false; } } return true; // If they *all* passed, we pass - }else{ + } else { return false; // Pattern is array, rule isn't } } diff --git a/package.json b/package.json index 4cbbfd4..10b0fd3 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ }, "dependencies": {}, "devDependencies": { - "eslint": "^3.9.1", - "eslint-config-google": "^0.7.0", + "eslint": "^7.11.0", + "eslint-config-google": "^0.14.0", "gulp": "^3.9.0", "qunit": "^0.7.7", "request": "^2.65.0" diff --git a/tests/testrunner.js b/tests/testrunner.js index e1dbb08..1aa2509 100644 --- a/tests/testrunner.js +++ b/tests/testrunner.js @@ -1,17 +1,17 @@ var testrunner = require("qunit"); testrunner.setup({ - log: { - summary: true, - errors: true - } + log: { + summary: true, + errors: true, + }, }); // specify dependency testrunner.run({ - code: "../logic.js", - tests: "tests.js" + code: "../logic.js", + tests: "tests.js", }, function(err, report) { - if(err) console.dir(err); - // console.dir(report); + if (err) console.dir(err); + // console.dir(report); }); diff --git a/tests/tests.js b/tests/tests.js index 8f8613b..90916d0 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -7,7 +7,7 @@ var download = function(url, dest, cb) { http.get(url, function(response) { response.pipe(file); file.on("finish", function() { - file.close(cb); // close() is async, call cb after close completes. + file.close(cb); // close() is async, call cb after close completes. }); }).on("error", function(err) { // Handle errors fs.unlink(dest); // Delete the file async. (But we don't check the result) @@ -15,18 +15,20 @@ var download = function(url, dest, cb) { }); }; -var remote_or_cache = function (remote_url, local_file, description, runner){ - var parse_and_iterate = function(local_file, description, runner){ +var remote_or_cache = function(remote_url, local_file, description, runner) { + var parse_and_iterate = function(local_file, description, runner) { fs.readFile(local_file, "utf8", function(error, body) { var tests; - try{ + try { tests = JSON.parse(body); - }catch(e) { + } catch (e) { throw new Error("Trouble parsing " + description + ": " + e.message); } // Remove comments - tests = tests.filter(function(test){ return typeof test !== 'string'; }); + tests = tests.filter(function(test) { + return typeof test !== "string"; + }); console.log("Including "+tests.length+" "+description); @@ -36,31 +38,29 @@ var remote_or_cache = function (remote_url, local_file, description, runner){ start(); }); - }; - // Only waiting on the request() is async + // Only waiting on the request() is async stop(); fs.stat(local_file, function(err, stats) { - if(err) { + if (err) { console.log("Downloading " + description + " from JsonLogic.com"); download(remote_url, local_file, function() { parse_and_iterate(local_file, description, runner); }); - }else{ + } else { console.log("Using cached " + description); parse_and_iterate(local_file, description, runner); } }); - }; remote_or_cache( "http://jsonlogic.com/tests.json", "tests.json", "applies() tests", - function(test){ + function(test) { var rule = test[0]; var data = test[1]; var expected = test[2]; @@ -79,7 +79,7 @@ remote_or_cache( "http://jsonlogic.com/rule_like.json", "rule_like.json", "rule_like() tests", - function(test){ + function(test) { var rule = test[0]; var pattern = test[1]; var expected = test[2]; @@ -95,10 +95,6 @@ remote_or_cache( ); - - - - QUnit.test( "Bad operator", function( assert ) { assert.throws( function() { @@ -140,7 +136,7 @@ QUnit.test( "Expanding functionality with add_operator", function( assert) { // Set up some outside data, and build a basic function operator var a = 0; var add_to_a = function(b) { - if(b === undefined) { + if (b === undefined) { b=1; } return a += b; }; @@ -178,12 +174,12 @@ QUnit.test( "Expanding functionality with add_operator", function( assert) { 42 ); - //Remove operation: + // Remove operation: jsonLogic.rm_operation("times"); assert.throws( function() { - jsonLogic.apply({"times": [2,2]}); + jsonLogic.apply({"times": [2, 2]}); }, /Unrecognized operation/ ); @@ -199,9 +195,6 @@ QUnit.test( "Expanding functionality with add_operator", function( assert) { ), 42 ); - - - }); QUnit.test("Control structures don't eval depth-first", function(assert) {