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; }