From 7321a7be17e48868495a177e7ab3e690fdf84c9f Mon Sep 17 00:00:00 2001 From: "Shelly (6utt3rfly)" <17912877+6utt3rfly@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:34:18 -0700 Subject: [PATCH 1/6] feat: add nullish coallescing (??) and exponentiation (**) binary_ops fixes #268 --- src/jsep.js | 8 +++++--- test/jsep.test.js | 50 +++++++++++++++++++++++++++++++++++++++++++--- test/test_utils.js | 1 + 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/jsep.js b/src/jsep.js index 31ee509..aa547eb 100644 --- a/src/jsep.js +++ b/src/jsep.js @@ -935,16 +935,18 @@ Object.assign(Jsep, { // binary precedence for quick reference (higher number = higher precedence) // see [Order of operations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) binary_ops: { - '||': 1, '&&': 2, '|': 3, '^': 4, '&': 5, + '||': 1, '??': 1, + '&&': 2, '|': 3, '^': 4, '&': 5, '==': 6, '!=': 6, '===': 6, '!==': 6, '<': 7, '>': 7, '<=': 7, '>=': 7, '<<': 8, '>>': 8, '>>>': 8, '+': 9, '-': 9, - '*': 10, '/': 10, '%': 10 + '*': 10, '/': 10, '%': 10, + '**': 11, }, // sets specific binary_ops as right-associative - right_associative: new Set(), + right_associative: new Set(['**']), // Additional valid identifier chars, apart from a-z, A-Z and 0-9 (except on the starting char) additional_identifier_chars: new Set(['$', '_']), diff --git a/test/jsep.test.js b/test/jsep.test.js index 4640ad4..6c63fa8 100644 --- a/test/jsep.test.js +++ b/test/jsep.test.js @@ -74,9 +74,6 @@ import {testParser, testOpExpression, esprimaComparisonTest, resetJsepDefaults} }); QUnit.module('Ops', function (qunit) { - qunit.before(() => { - jsep.addBinaryOp('**', 11, true); // ES2016, right-associative - }); qunit.after(resetJsepDefaults); [ @@ -93,6 +90,7 @@ import {testParser, testOpExpression, esprimaComparisonTest, resetJsepDefaults} '2 ** 3 ** 4', '2 ** 3 ** 4 * 5 ** 6 ** 7 * (8 + 9)', '(2 ** 3) ** 4 * (5 ** 6 ** 7) * (8 + 9)', + 'null ?? 1', ].forEach(expr => QUnit.test(`Expr: ${expr}`, assert => testOpExpression(expr, assert))); }); @@ -153,6 +151,51 @@ import {testParser, testOpExpression, esprimaComparisonTest, resetJsepDefaults} jsep.removeUnaryOp('notes'); }); + QUnit.test('Right-Associative Operators', function (assert) { + testParser('a ** b ** c', { // right-associative + type: 'BinaryExpression', + operator: '**', + left: { + type: 'Identifier', + name: 'a', + }, + right: { + type: 'BinaryExpression', + operator: '**', + left: { + type: 'Identifier', + name: 'b', + }, + right: { + type: 'Identifier', + name: 'c' + } + } + }, assert); + + const expr = 'a * b * c'; + testParser(expr, { + type: 'BinaryExpression', + operator: '*', + left: { + type: 'BinaryExpression', + operator: '*', + left: { + type: 'Identifier', + name: 'a' + }, + right: { + type: 'Identifier', + name: 'b' + } + }, + right: { + type: 'Identifier', + name: 'c', + } + }, assert); + }); + QUnit.test('Custom alphanumeric operators', function (assert) { jsep.addBinaryOp('and', 2); testParser('a and b', { @@ -231,6 +274,7 @@ import {testParser, testOpExpression, esprimaComparisonTest, resetJsepDefaults} '*x', '||x', '?a:b', + 'a ??', '.', '()()', // '()', should throw 'unexpected )'... diff --git a/test/test_utils.js b/test/test_utils.js index 8cb8053..ebd63d8 100644 --- a/test/test_utils.js +++ b/test/test_utils.js @@ -7,6 +7,7 @@ export const binOps = { '/': (a, b) => a / b, '%': (a, b) => a % b, '**': (a, b) => a ** b, // ES2016 + '??': (a, b) => a ?? b, // ES2020 }; export const unOps = { From 773a0631785648862baceb76ba5c5574237fe999 Mon Sep 17 00:00:00 2001 From: "Shelly (6utt3rfly)" <17912877+6utt3rfly@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:35:57 -0700 Subject: [PATCH 2/6] feat: add logical assignment operators ||= &&= ??= (es2021) --- packages/assignment/src/index.js | 3 +++ packages/assignment/test/index.test.js | 5 ++++- packages/assignment/types/tsd.d.ts | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/assignment/src/index.js b/packages/assignment/src/index.js index 2f83627..39c7552 100644 --- a/packages/assignment/src/index.js +++ b/packages/assignment/src/index.js @@ -18,6 +18,9 @@ const plugin = { '&=', '^=', '|=', + '||=', + '&&=', + '??=', ]), updateOperators: [PLUS_CODE, MINUS_CODE], assignmentPrecedence: 0.9, diff --git a/packages/assignment/test/index.test.js b/packages/assignment/test/index.test.js index efad5ba..3247be3 100644 --- a/packages/assignment/test/index.test.js +++ b/packages/assignment/test/index.test.js @@ -20,6 +20,9 @@ const { test } = QUnit; '&=', '^=', '|=', + '||=', + '&&=', + '??=', ]; qunit.before(() => jsep.plugins.register(assignment)); @@ -234,7 +237,7 @@ const { test } = QUnit; [ ...operators - .filter(op => op !== '**=') // not supported by esprima + .filter(op => !['**=', '||=', '&&=', '??='].includes(op)) // not supported by esprima .map(op => `a ${op} 2`), 'a++', '++a', diff --git a/packages/assignment/types/tsd.d.ts b/packages/assignment/types/tsd.d.ts index efd847c..d6af5e0 100644 --- a/packages/assignment/types/tsd.d.ts +++ b/packages/assignment/types/tsd.d.ts @@ -27,7 +27,10 @@ export interface AssignmentExpression extends Expression { | '>>>=' | '&=' | '^=' - | '|='; + | '|=' + | '||=' + | '&&=' + | '??='; left: Expression; right: Expression; } From f6678fb0869188e9c9575fed231864f75e99af74 Mon Sep 17 00:00:00 2001 From: "Shelly (6utt3rfly)" <17912877+6utt3rfly@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:03:08 -0700 Subject: [PATCH 3/6] fix: add license file to build output fixes #267 --- packages/arrow/package.json | 2 +- packages/assignment/package.json | 2 +- packages/async-await/package.json | 2 +- packages/comment/package.json | 2 +- packages/new/package.json | 2 +- packages/numbers/package.json | 2 +- packages/object/package.json | 2 +- packages/regex/package.json | 2 +- packages/spread/package.json | 2 +- packages/template/package.json | 2 +- packages/ternary/package.json | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/arrow/package.json b/packages/arrow/package.json index 8e2fbc8..13d3d07 100644 --- a/packages/arrow/package.json +++ b/packages/arrow/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/arrow/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/assignment/package.json b/packages/assignment/package.json index 2069b6b..6de6021 100644 --- a/packages/assignment/package.json +++ b/packages/assignment/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/assignment/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/async-await/package.json b/packages/async-await/package.json index b72ef79..d7d25c5 100644 --- a/packages/async-await/package.json +++ b/packages/async-await/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/async-await/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/comment/package.json b/packages/comment/package.json index 0700d8a..60d7589 100644 --- a/packages/comment/package.json +++ b/packages/comment/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/comment/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/new/package.json b/packages/new/package.json index cb2fe6c..50d989b 100644 --- a/packages/new/package.json +++ b/packages/new/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/new/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/numbers/package.json b/packages/numbers/package.json index e4f1e17..2630aec 100644 --- a/packages/numbers/package.json +++ b/packages/numbers/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/numbers/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/object/package.json b/packages/object/package.json index 20610b2..2a93db3 100644 --- a/packages/object/package.json +++ b/packages/object/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/object/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/regex/package.json b/packages/regex/package.json index 3b21000..bb22baa 100644 --- a/packages/regex/package.json +++ b/packages/regex/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/regex/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/spread/package.json b/packages/spread/package.json index 201b44c..8db3027 100644 --- a/packages/spread/package.json +++ b/packages/spread/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/spread/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/template/package.json b/packages/template/package.json index 7330cf1..753b8fe 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/template/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } diff --git a/packages/ternary/package.json b/packages/ternary/package.json index a62cdab..92eac2e 100644 --- a/packages/ternary/package.json +++ b/packages/ternary/package.json @@ -32,7 +32,7 @@ "node": ">= 10.16.0" }, "scripts": { - "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json", + "build": "rollup -c ../../plugin.rollup.config.js && cp ../../package-cjs.json dist/cjs/package.json && cp ../../LICENSE ./", "test": "cd ../../ && http-server -p 49649 --silent & node-qunit-puppeteer http://localhost:49649/packages/ternary/test/unit_tests.html", "lint": "eslint src/**/*.js test/**/*.js" } From a704d8949928bb6716cf8799b8ec620968d8f483 Mon Sep 17 00:00:00 2001 From: "Shelly (6utt3rfly)" <17912877+6utt3rfly@users.noreply.github.com> Date: Sun, 27 Oct 2024 13:24:50 -0700 Subject: [PATCH 4/6] docs: add docs for standard JS literals fixes #255 --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 28e4bda..36a93fd 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ const parse_tree = Jsep.parse('1 + 1'); jsep.addBinaryOp("^", 10); // Add exponentiation operator (right-to-left) -jsep.addBinaryOp('**', 11, true); +jsep.addBinaryOp('**', 11, true); // now included by default // Add a custom @ unary operator jsep.addUnaryOp('@'); @@ -89,6 +89,19 @@ jsep.addIdentifierChar("@"); jsep.removeIdentifierChar('@'); ``` +#### Custom Literals + +You can add or remove additional valid literals. By default, only `true`, `false`, and `null` are defined +```javascript +// Add standard JS literals: +jsep.addLiteral('undefined', undefined); +jsep.addLiteral('Infinity', Infinity); +jsep.addLiteral('NaN', NaN); + +// Remove "null" literal from default definition +jsep.removeLiteral('null'); +``` + ### Plugins JSEP supports defining custom hooks for extending or modifying the expression parsing. Plugins are registered by calling `jsep.plugins.register()` with the plugin(s) as the argument(s). From 404a880e8e3aefc3abf8a58cd0d85059a22123fa Mon Sep 17 00:00:00 2001 From: "Shelly (6utt3rfly)" <17912877+6utt3rfly@users.noreply.github.com> Date: Sun, 27 Oct 2024 13:29:38 -0700 Subject: [PATCH 5/6] build: remove node 16, add node 18 to test builds --- .github/workflows/node.js.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f09a9b8..64666f9 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - node-version: [16.x, 18.x, 20.x] + node-version: [18.x, 20.x, 22.x] steps: - uses: actions/checkout@v4 From 7f38f1219ad5a5a8c364ff50063148a1dc8ba081 Mon Sep 17 00:00:00 2001 From: "Shelly (6utt3rfly)" <17912877+6utt3rfly@users.noreply.github.com> Date: Sun, 27 Oct 2024 13:47:35 -0700 Subject: [PATCH 6/6] test: update eslint rules to es2020 and upgrade docco --- .eslintrc.json | 10 +--------- package.json | 2 +- pnpm-lock.yaml | 32 ++++++++++++++++---------------- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 1abc828..6027711 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,7 +1,7 @@ { "ignorePatterns": ["**/dist/**/*.js"], "parserOptions": { - "ecmaVersion": 6, + "ecmaVersion": 2020, "sourceType": "module", "ecmaFeatures": { "impliedStrict": true @@ -11,14 +11,6 @@ "browser": true, "node": true }, - "overrides": [ - { - "files": ["test/**/*.js", "*.test.js"], - "parserOptions": { - "ecmaVersion": 7 - } - } - ], "rules": { "semi": 1, "no-dupe-args": 1, diff --git a/package.json b/package.json index 2579e4f..8f25e5a 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^9.0.0", "benchmark": "^2.1.4", - "docco": "^0.8.1", + "docco": "^0.9.1", "eslint": "^7.23.0", "http-server": "^14.1.1", "husky": "^7.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5ecf38e..c88e2df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,7 +11,7 @@ importers: '@semantic-release/exec': ^6.0.3 '@semantic-release/git': ^9.0.0 benchmark: ^2.1.4 - docco: ^0.8.1 + docco: ^0.9.1 eslint: ^7.23.0 http-server: ^14.1.1 husky: ^7.0.0 @@ -30,7 +30,7 @@ importers: '@semantic-release/exec': 6.0.3 '@semantic-release/git': 9.0.0 benchmark: 2.1.4 - docco: 0.8.1 + docco: 0.9.1 eslint: 7.32.0 http-server: 14.1.1 husky: 7.0.2 @@ -1037,8 +1037,8 @@ packages: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true - /commander/8.1.0: - resolution: {integrity: sha512-mf45ldcuHSYShkplHHGKWb4TrmwQadxOn7v4WuhDJy0ZVoY5JFajaRDKD0PNe5qXzBX0rhovjTnP6Kz9LETcuA==} + /commander/8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} dev: true @@ -1269,15 +1269,15 @@ packages: path-type: 4.0.0 dev: true - /docco/0.8.1: - resolution: {integrity: sha512-OFVdjpxw4aTI+FThrCY2NEWZV/nvGDFlfeQxUTMkKL+oY2gD2sMl0N5ogoAj3YLZU05UDBSh64ROYzLFzxSoSQ==} + /docco/0.9.1: + resolution: {integrity: sha512-B1jUzcAc4AmicWUnmPTxUGM2lqJ11X4DiLUXyhzUVb7A1NNGTSNo3LtGzhHMyRAuJyxrHwHiOCDGuE/n9xRhmA==} engines: {node: '>=0.2.0'} hasBin: true dependencies: - commander: 8.1.0 + commander: 8.3.0 fs-extra: 10.0.0 - highlight.js: 11.2.0 - marked: 2.1.3 + highlight.js: 11.3.1 + marked: 4.0.19 underscore: 1.13.1 dev: true @@ -1855,8 +1855,8 @@ packages: hasBin: true dev: true - /highlight.js/11.2.0: - resolution: {integrity: sha512-JOySjtOEcyG8s4MLR2MNbLUyaXqUunmSnL2kdV/KuGJOmHZuAR5xC54Ko7goAXBWNhf09Vy3B+U7vR62UZ/0iw==} + /highlight.js/11.3.1: + resolution: {integrity: sha512-PUhCRnPjLtiLHZAQ5A/Dt5F8cWZeMyj9KRsACsWT+OD6OP0x6dp5OmT5jdx0JgEyPxPZZIPQpRN2TciUT7occw==} engines: {node: '>=12.0.0'} dev: true @@ -2319,14 +2319,14 @@ packages: supports-hyperlinks: 2.2.0 dev: true - /marked/2.1.3: - resolution: {integrity: sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==} - engines: {node: '>= 10'} + /marked/3.0.2: + resolution: {integrity: sha512-TMJQQ79Z0e3rJYazY0tIoMsFzteUGw9fB3FD+gzuIT3zLuG9L9ckIvUfF51apdJkcqc208jJN2KbtPbOvXtbjA==} + engines: {node: '>= 12'} hasBin: true dev: true - /marked/3.0.2: - resolution: {integrity: sha512-TMJQQ79Z0e3rJYazY0tIoMsFzteUGw9fB3FD+gzuIT3zLuG9L9ckIvUfF51apdJkcqc208jJN2KbtPbOvXtbjA==} + /marked/4.0.19: + resolution: {integrity: sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ==} engines: {node: '>= 12'} hasBin: true dev: true