From 25035d97a4969c60e9e90ae71e66180fee65723b Mon Sep 17 00:00:00 2001 From: John Brinkman Date: Tue, 9 Jul 2024 10:10:37 -0400 Subject: [PATCH 1/5] https://github.com/adobe/json-formula/issues/178 --- package.json | 2 +- src/TreeInterpreter.js | 2 +- test/tests.json | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 701e1be8..6c4f2d7d 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "eslint": "^8.56.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-jest": "^28.5.0", "html-inline-script-webpack-plugin": "^3.1.0", "html-webpack-plugin": "^5.6.0", "jest": "^29.3.1", diff --git a/src/TreeInterpreter.js b/src/TreeInterpreter.js index c8b90b13..4a478002 100644 --- a/src/TreeInterpreter.js +++ b/src/TreeInterpreter.js @@ -93,7 +93,7 @@ export default class TreeInterpreter { return null; } - visit(n, v) { + visit(n, v = null) { const visitFunctions = { Identifier: this.field.bind(this), QuotedIdentifier: this.field.bind(this), diff --git a/test/tests.json b/test/tests.json index fab377a0..84b4316a 100644 --- a/test/tests.json +++ b/test/tests.json @@ -1573,6 +1573,10 @@ "expression": "merge(register(\"_p1\", &42), register(\"_p2\", &43), {r: _p1() + _p2()})", "result": { "r": 85 } }, + { + "expression": "register(\"_identity\", &@) || _identity()", + "result": null + }, { "expression": "register(\"\", &42)", "error": "FunctionError" From e32bbf097e6bd71475ea0f394b6a4b312872365c Mon Sep 17 00:00:00 2001 From: John Brinkman Date: Tue, 9 Jul 2024 13:07:46 -0400 Subject: [PATCH 2/5] https://github.com/adobe/json-formula/issues/179 --- doc/spec.adoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/spec.adoc b/doc/spec.adoc index e88e4f43..2ad47b04 100644 --- a/doc/spec.adoc +++ b/doc/spec.adoc @@ -301,10 +301,11 @@ fragment EXP ; ---- -Number literals follow the same syntax rules as numeric values in JSON with two exceptions: +Number literals follow the same syntax rules as numeric values in JSON with three exceptions: 1. Number literals may omit a leading zero. For example, `.123` is not valid JSON, but is allowed as a number literal. -2. The grammar construction for a number literal does not include a minus sign. Literal expressions are made negative by prefixing them with a unary minus. +2. Number literals may include a leading zero. For example, `0123` is not valid JSON, but is allowed as a number literal. +3. The grammar construction for a number literal does not include a minus sign. Literal expressions are made negative by prefixing them with a unary minus. Note that number literals (and JSON numbers) allow scientific notation. From 1bc5151a29ea67331aeaa31b4eb25c38a9905f91 Mon Sep 17 00:00:00 2001 From: John Brinkman Date: Tue, 9 Jul 2024 13:08:19 -0400 Subject: [PATCH 3/5] allow whitespace and +/- indicators in numeric strings. Do not allow 0x, 0b, 0o as indicators of different radixes. --- src/functions.js | 6 +++--- src/stringToNumber.js | 1 + test/functions.json | 22 ++++++++++++++++++++++ test/tests.json | 6 ++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/functions.js b/src/functions.js index 6537d7b1..7995d637 100644 --- a/src/functions.js +++ b/src/functions.js @@ -2181,9 +2181,9 @@ export default function functions( const base = resolvedArgs.length > 1 ? toInteger(resolvedArgs[1]) : 10; if (getType(num) === TYPE_STRING && base !== 10) { let digitCheck; - if (base === 2) digitCheck = /^[01.]+$/; - else if (base === 8) digitCheck = /^[0-7.]+$/; - else if (base === 16) digitCheck = /^[0-9A-Fa-f.]+$/; + if (base === 2) digitCheck = /^\s*(\+|-)?[01.]+\s*$/; + else if (base === 8) digitCheck = /^\s*(\+|-)?[0-7.]+\s*$/; + else if (base === 16) digitCheck = /^\s*(\+|-)?[0-9A-Fa-f.]+\s*$/; else throw evaluationError(`Invalid base: "${base}" for toNumber()`); if (num === '') return 0; diff --git a/src/stringToNumber.js b/src/stringToNumber.js index cb3a9b41..aa8f747d 100644 --- a/src/stringToNumber.js +++ b/src/stringToNumber.js @@ -13,6 +13,7 @@ governing permissions and limitations under the License. import { typeError } from './errors.js'; export default function stringToNumber(n) { + if (!/^\s*(-|\+)?(\d*)(\.\d+)?(e(\+|-)?\d+)?\s*$/i.test(n)) throw typeError(`Failed to convert "${n}" to number`); const ret = +n; if (Number.isNaN(ret)) { throw typeError(`Failed to convert "${n}" to number`); diff --git a/test/functions.json b/test/functions.json index 45479b77..7a66a97f 100644 --- a/test/functions.json +++ b/test/functions.json @@ -984,6 +984,28 @@ "expression": "toNumber(toNum.n11, 16)", "result": 11 }, + { + "expression": "toNumber(\"0x11\")", + "result": null + }, + { + "expression": "toNumber(\"0o11\")", + "result": null + }, + { + "expression": "toNumber(\"0b11\")", + "result": null + }, + { "expression": "toNumber(\" 01e01\\n\")", "result": 10}, + { "expression": "toNumber(\" 011\\n\", 2)", "result": 3}, + { "expression": "toNumber(\" -011\\n\", 2)", "result": -3}, + { "expression": "toNumber(\" +011\\n\", 2)", "result": 3}, + { "expression": "toNumber(\" 011\\n\", 16)", "result": 17}, + { "expression": "toNumber(\" -011\\n\", 16)", "result": -17}, + { "expression": "toNumber(\" +011\\n\", 16)", "result": 17}, + { "expression": "toNumber(\" 011\\n\", 8)", "result": 9}, + { "expression": "toNumber(\" -011\\n\", 8)", "result": -9}, + { "expression": "toNumber(\" +011\\n\", 8)", "result": 9}, { "expression": "'toString'(`1.0`)", "error": "SyntaxError" diff --git a/test/tests.json b/test/tests.json index 84b4316a..e9a211ba 100644 --- a/test/tests.json +++ b/test/tests.json @@ -146,6 +146,12 @@ { "expression": "sum([2,\"4\",6,`true`])", "result": 13 }, { "expression": "(3 + 2) * 10 / 2 - 5", "result": 20 }, { "expression": "2 * \"$2\" + `null`", "error": "TypeError" }, + { "expression": "\"0x11\" * 1", "error": "TypeError"}, + { "expression": "\"0b11\" * 1", "error": "TypeError"}, + { "expression": "\"0o11\" * 1", "error": "TypeError"}, + { "expression": "1+\"01e01\"", "result": 11}, + { "expression": "1*\" +011e+01\\n\"", "result": 110}, + { "expression": "1*\" -011e-01\\n\"", "result": -1.1}, { "expression": "1 < 2", "result": true }, { "expression": "1 > 2", "result": false }, { "expression": "12 >= 12", "result": true }, From 9844555ee99e6858d83a43d87dac24e1e9e14fe0 Mon Sep 17 00:00:00 2001 From: John Brinkman Date: Tue, 9 Jul 2024 13:15:14 -0400 Subject: [PATCH 4/5] revert change to eslint-plugin-jest --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c4f2d7d..701e1be8 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "eslint": "^8.56.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^28.5.0", + "eslint-plugin-jest": "^27.6.0", "html-inline-script-webpack-plugin": "^3.1.0", "html-webpack-plugin": "^5.6.0", "jest": "^29.3.1", From 301324a9195314b4eb370f12be1492e209b700b3 Mon Sep 17 00:00:00 2001 From: John Brinkman Date: Tue, 9 Jul 2024 14:45:23 -0400 Subject: [PATCH 5/5] clarify numeric literals --- doc/spec.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/spec.adoc b/doc/spec.adoc index 2ad47b04..2c5c5861 100644 --- a/doc/spec.adoc +++ b/doc/spec.adoc @@ -303,8 +303,8 @@ fragment EXP Number literals follow the same syntax rules as numeric values in JSON with three exceptions: -1. Number literals may omit a leading zero. For example, `.123` is not valid JSON, but is allowed as a number literal. -2. Number literals may include a leading zero. For example, `0123` is not valid JSON, but is allowed as a number literal. +1. Number literals may omit a leading zero before the decimal point. For example, `.123` is not valid JSON, but is allowed as a number literal. +2. Number literals may include leading zeros ahead of the integral part of the number. For example, `0123` is not valid JSON, but is allowed as a number literal. 3. The grammar construction for a number literal does not include a minus sign. Literal expressions are made negative by prefixing them with a unary minus. Note that number literals (and JSON numbers) allow scientific notation.