diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 2f3630e..f09a9b8 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -14,22 +14,22 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x, 18.x] + node-version: [16.x, 18.x, 20.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Cache pnpm modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.pnpm-store key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}- - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@v4 with: version: ^7 run_install: true diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 8bca4c7..bf5c4e8 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -15,21 +15,21 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [20.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Cache pnpm modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.pnpm-store key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}- - - uses: pnpm/action-setup@v2.0.1 + - uses: pnpm/action-setup@v4 with: version: 6.0.2 run_install: true diff --git a/README.md b/README.md index 13d8157..28e4bda 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ export interface HookScope { gobbleArguments: (untilICode: number) => PossibleExpression; gobbleGroup: () => Expression; gobbleArray: () => PossibleExpression; - throwError: (msg: string) => void; + throwError: (msg: string) => never; } ``` diff --git a/src/jsep.js b/src/jsep.js index 00944cc..31ee509 100644 --- a/src/jsep.js +++ b/src/jsep.js @@ -589,6 +589,9 @@ export class Jsep { object: node, property: this.gobbleExpression() }; + if (!node.property) { + this.throwError('Unexpected "' + this.char + '"'); + } this.gobbleSpaces(); ch = this.code; if (ch !== Jsep.CBRACK_CODE) { @@ -963,12 +966,11 @@ Jsep.max_binop_len = Jsep.getMaxKeyLen(Jsep.binary_ops); // Backward Compatibility: const jsep = expr => (new Jsep(expr)).parse(); -const staticMethods = Object.getOwnPropertyNames(Jsep); -staticMethods +const stdClassProps = Object.getOwnPropertyNames(class Test{}); +Object.getOwnPropertyNames(Jsep) + .filter(prop => !stdClassProps.includes(prop) && jsep[prop] === undefined) .forEach((m) => { - if (jsep[m] === undefined && m !== 'prototype') { - jsep[m] = Jsep[m]; - } + jsep[m] = Jsep[m]; }); jsep.Jsep = Jsep; // allows for const { Jsep } = require('jsep'); export default jsep; diff --git a/test/jsep.test.js b/test/jsep.test.js index 7c1909f..4640ad4 100644 --- a/test/jsep.test.js +++ b/test/jsep.test.js @@ -39,6 +39,7 @@ import {testParser, testOpExpression, esprimaComparisonTest, resetJsepDefaults} type: 'MemberExpression', optional: true, }, assert); + assert.throws(() => jsep('[1,2][]'), 'Unexpected "]"'); }); QUnit.test('Function Calls', function (assert) { @@ -54,7 +55,18 @@ import {testParser, testOpExpression, esprimaComparisonTest, resetJsepDefaults} QUnit.test('Arrays', function (assert) { testParser('[]', { type: 'ArrayExpression', elements: [] }, assert); - + testParser('[,,1]', { + type: 'ArrayExpression', + elements: [ + null, + null, + { + raw: '1', + type: 'Literal', + value: 1 + } + ], + }, assert); testParser('[a]', { type: 'ArrayExpression', elements: [{ type: 'Identifier', name: 'a' }], diff --git a/typings/tsd.d.ts b/typings/tsd.d.ts index 46f8212..002be1c 100644 --- a/typings/tsd.d.ts +++ b/typings/tsd.d.ts @@ -9,7 +9,8 @@ declare module 'jsep' { export interface ArrayExpression extends Expression { type: 'ArrayExpression'; - elements: Expression[]; + /** The expression can be null in the case of array holes ([ , , ]) */ + elements: Array; } export interface BinaryExpression extends Expression { @@ -30,6 +31,11 @@ declare module 'jsep' { body: Expression[]; } + export interface SequenceExpression extends Expression { + type: 'SequenceExpression'; + expressions: Expression[]; + } + export interface ConditionalExpression extends Expression { type: 'ConditionalExpression'; test: Expression; @@ -69,6 +75,7 @@ declare module 'jsep' { export type ExpressionType = 'Compound' + | 'SequenceExpression' | 'Identifier' | 'MemberExpression' | 'Literal' @@ -84,6 +91,7 @@ declare module 'jsep' { | BinaryExpression | CallExpression | Compound + | SequenceExpression | ConditionalExpression | Identifier | Literal @@ -110,7 +118,7 @@ declare module 'jsep' { gobbleArguments: (untilICode: number) => PossibleExpression; gobbleGroup: () => Expression; gobbleArray: () => PossibleExpression; - throwError: (msg: string) => void; + throwError: (msg: string) => never; } export type HookType = 'gobble-expression' | 'after-expression' | 'gobble-token' | 'after-token' | 'gobble-spaces'; @@ -145,14 +153,24 @@ declare module 'jsep' { function addUnaryOp(operatorName: string): void; + function addLiteral(literalName: string, literalValue: any): void; + + function addIdentifierChar(identifierName: string): void; + function removeBinaryOp(operatorName: string): void; function removeUnaryOp(operatorName: string): void; - function addIdentifierChar(identifierName: string): void; + function removeLiteral(literalName: string): void; function removeIdentifierChar(identifierName: string): void; + function removeAllBinaryOps(): void; + + function removeAllUnaryOps(): void; + + function removeAllLiterals(): void; + const version: string; }