Repository: jsonata-js/jsonata
Pull request #381 (2019-10-16 14:12:08)

Add typeOf() function.
Proposed in https://github.com/jsonata-js/jsonata/issues/208

coveralls: 
[![Coverage Status](https://coveralls.io/builds/26350028/badge)](https://coveralls.io/builds/26350028)

Coverage remained the same at 100.0% when pulling **b3aea78f0a1d7ace5b5808bc9cf0be3b091a8d04 on elasticio:add-typeof-function** into **d5cbeccba0598b53f6f2ae6d60b066f48beebebf on jsonata-js:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/26350028/badge)](https://coveralls.io/builds/26350028)

Coverage remained the same at 100.0% when pulling **b3aea78f0a1d7ace5b5808bc9cf0be3b091a8d04 on elasticio:add-typeof-function** into **d5cbeccba0598b53f6f2ae6d60b066f48beebebf on jsonata-js:master**.

andrew-coleman: excellent - many thanks!

Patch:
diff --git a/docs/object-functions.md b/docs/object-functions.md
index 56f0c99..6dc8b61 100644
--- a/docs/object-functions.md
+++ b/docs/object-functions.md
@@ -53,12 +53,27 @@ __Examples__
       "Postcode: SO21 2JN"
     ]
 
- ## `$error()`
+## `$error()`
 __Signature:__`$error(message)`
 
 Deliberately throws an error with an optional `message`
 
- ## `$assert()`
+## `$assert()`
 __Signature:__`$assert(condition, message)`
 
 If condition is true, the function returns undefined. If the condition is false, an exception is thrown with the message as the message of the exception.
+
+## `$type()`
+__Signature:__`$type(value)`
+
+Evaluates the type of `value` and returns one of the following strings:
+* `"null"`
+* `"number"`
+* `"string"`
+* `"boolean"`
+* `"array"`
+* `"object"`
+* `"function"`
+Returns (non-string) `undefined` when `value` is `undefined`.
+
+
diff --git a/src/functions.js b/src/functions.js
index cc2f324..39b7195 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -1841,6 +1841,43 @@ const functions = (() => {
         return undefined;
     }
 
+    /**
+     *
+     * @param {*} [value] - the input to which the type will be checked
+     * @returns {string} - the type of the input
+     */
+    function type(value) {
+        if (value === undefined) {
+            return undefined;
+        }
+
+        if (value === null) {
+            return 'null';
+        }
+
+        if (isNumeric(value)) {
+            return 'number';
+        }
+
+        if (typeof value === 'string') {
+            return 'string';
+        }
+
+        if (typeof value === 'boolean') {
+            return 'boolean';
+        }
+
+        if(Array.isArray(value)) {
+            return 'array';
+        }
+
+        if(isFunction(value)) {
+            return 'function';
+        }
+
+        return 'object';
+    }
+
     /**
      * Implements the merge sort (stable) with optional comparator function
      *
@@ -2014,7 +2051,7 @@ const functions = (() => {
         formatNumber, formatBase, number, floor, ceil, round, abs, sqrt, power, random,
         boolean, not,
         map, zip, filter, single, foldLeft, sift,
-        keys, lookup, append, exists, spread, merge, reverse, each, error, assert, sort, shuffle, distinct,
+        keys, lookup, append, exists, spread, merge, reverse, each, error, assert, type, sort, shuffle, distinct,
         base64encode, base64decode,  encodeUrlComponent, encodeUrl, decodeUrlComponent, decodeUrl
     };
 })();
diff --git a/src/jsonata.js b/src/jsonata.js
index ebccb06..df12d7a 100644
--- a/src/jsonata.js
+++ b/src/jsonata.js
@@ -1859,6 +1859,7 @@ var jsonata = (function() {
     staticFrame.bind('each', defineFunction(fn.each, '<o-f:a>'));
     staticFrame.bind('error', defineFunction(fn.error, '<s?:x>'));
     staticFrame.bind('assert', defineFunction(fn.assert, '<bs?:x>'));
+    staticFrame.bind('type', defineFunction(fn.type, '<x:s>'));
     staticFrame.bind('sort', defineFunction(fn.sort, '<af?:a>'));
     staticFrame.bind('shuffle', defineFunction(fn.shuffle, '<a:a>'));
     staticFrame.bind('distinct', defineFunction(fn.distinct, '<x:x>'));


Test patch:
diff --git a/test/test-suite/groups/function-typeOf/case001.json b/test/test-suite/groups/function-typeOf/case001.json
new file mode 100644
index 0000000..8c8d1f5
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case001.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= undefined; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "undefinedResult": true
+}
diff --git a/test/test-suite/groups/function-typeOf/case002.json b/test/test-suite/groups/function-typeOf/case002.json
new file mode 100644
index 0000000..025c166
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case002.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= null; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "null" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case003.json b/test/test-suite/groups/function-typeOf/case003.json
new file mode 100644
index 0000000..efb4031
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case003.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= 123; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "number" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case004.json b/test/test-suite/groups/function-typeOf/case004.json
new file mode 100644
index 0000000..18fb589
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case004.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= '123'; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "string" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case005.json b/test/test-suite/groups/function-typeOf/case005.json
new file mode 100644
index 0000000..b610b43
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case005.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= true; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "boolean" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case006.json b/test/test-suite/groups/function-typeOf/case006.json
new file mode 100644
index 0000000..441af45
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case006.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= 'true'; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "string" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case007.json b/test/test-suite/groups/function-typeOf/case007.json
new file mode 100644
index 0000000..a4cc95b
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case007.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= []; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "array" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case008.json b/test/test-suite/groups/function-typeOf/case008.json
new file mode 100644
index 0000000..3213b9d
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case008.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= ['a']; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "array" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case009.json b/test/test-suite/groups/function-typeOf/case009.json
new file mode 100644
index 0000000..69e92a5
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case009.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= ['a','b']; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "array" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case010.json b/test/test-suite/groups/function-typeOf/case010.json
new file mode 100644
index 0000000..2532e24
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case010.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= function(){true}; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "function" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case011.json b/test/test-suite/groups/function-typeOf/case011.json
new file mode 100644
index 0000000..a78d1ca
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case011.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= (λ($v, $i, $a) {$v.price = $max($a.price)}); $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "function" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case012.json b/test/test-suite/groups/function-typeOf/case012.json
new file mode 100644
index 0000000..08f38e6
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case012.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= {}; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "object" 
+}
diff --git a/test/test-suite/groups/function-typeOf/case013.json b/test/test-suite/groups/function-typeOf/case013.json
new file mode 100644
index 0000000..0d23c65
--- /dev/null
+++ b/test/test-suite/groups/function-typeOf/case013.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($var:= {\"foo\":\"bar\"}; $type($var))",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": "object" 
+}