Repository: jsonata-js/jsonata
Pull request #573 (2022-05-03 15:23:36)

Binary/Octal/Hexadecimal numbers
In the current implementation the $number() function does not allow the conversion of binary, octal or hexadecimal numbers. This PR changes that.

A regex is used to find such numbers with a given prefix (`0x` for hexadecimal, `0o` for octal, `0b` for binary). If a valid Number is found, JavaScript's built-in function `Number()` is used to convert the string to a number.

Tests and Documentation have been adapted.

Signed-off-by: Markus Gutbrod <gutbrod.markus@googlemail.com>

mattbaileyuk: Closing and reopening to see if that triggers Travis
coveralls: 
[![Coverage Status](https://coveralls.io/builds/48954753/badge)](https://coveralls.io/builds/48954753)

Coverage remained the same at 100.0% when pulling **7b4c810cd0286b2a2958b71894c14930bf99c12c on bigbug:master** into **b97c9d73c6552877133116b595a7817db443548e on jsonata-js:master**.

mattbaileyuk: Looks good, thanks for the contribution @bigbug 👍 

Patch:
diff --git a/docs/numeric-functions.md b/docs/numeric-functions.md
index 6421a66..422cdc8 100644
--- a/docs/numeric-functions.md
+++ b/docs/numeric-functions.md
@@ -10,6 +10,7 @@ __Signature:__ `$number(arg)`
 Casts the `arg` parameter to a number using the following casting rules
    - Numbers are unchanged
    - Strings that contain a sequence of characters that represent a legal JSON number are converted to that number
+   - Hexadecimal numbers start with `0x`, Octal numbers with `0o`, binary numbers with `0b`
    - Boolean `true` casts to `1`, Boolean `false` casts to `0`
    - All other values cause an error to be thrown.
 
@@ -17,6 +18,7 @@ If `arg` is not specified (i.e. this function is invoked with no arguments), the
 
 __Examples__  
 - `$number("5")` => `5`  
+- `$number("0x12")` => `0x18`  
 - `["1", "2", "3", "4", "5"].$number()` => `[1, 2, 3, 4, 5]`
 
 
diff --git a/src/functions.js b/src/functions.js
index 5b7bfb8..9c95c3f 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -1202,6 +1202,8 @@ const functions = (() => {
             result = arg;
         } else if (typeof arg === 'string' && /^-?[0-9]+(\.[0-9]+)?([Ee][-+]?[0-9]+)?$/.test(arg) && !isNaN(parseFloat(arg)) && isFinite(arg)) {
             result = parseFloat(arg);
+        } else if (typeof arg === 'string' && /^(0[xX][0-9A-Fa-f]+)|(0[oO][0-7]+)|(0[bB][0-1]+)$/.test(arg)) {
+            result = Number(arg);
         } else if (arg === true) {
             // boolean true casts to 1
             result = 1;


Test patch:
diff --git a/test/test-suite/groups/function-number/case031.json b/test/test-suite/groups/function-number/case031.json
new file mode 100644
index 0000000..3fb3f63
--- /dev/null
+++ b/test/test-suite/groups/function-number/case031.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$number('0x12')",
+    "dataset": null,
+    "bindings": {},
+    "result": 18
+}
diff --git a/test/test-suite/groups/function-number/case032.json b/test/test-suite/groups/function-number/case032.json
new file mode 100644
index 0000000..a4cd986
--- /dev/null
+++ b/test/test-suite/groups/function-number/case032.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$number('0B101')",
+    "dataset": null,
+    "bindings": {},
+    "result": 5
+}
diff --git a/test/test-suite/groups/function-number/case033.json b/test/test-suite/groups/function-number/case033.json
new file mode 100644
index 0000000..aabfa00
--- /dev/null
+++ b/test/test-suite/groups/function-number/case033.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$number('0O12')",
+    "dataset": null,
+    "bindings": {},
+    "result": 10
+}