From 2c90d9fa3aa5ebd7db697dddb7762bca2dd0e06b Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 18 Jul 2020 18:45:53 -0700 Subject: [PATCH] feat(typescript-estree): support short-circuiting assignment operators (#2307) --- .../lib/__snapshots__/typescript.ts.snap | 318 ++++++++++++++++++ ...short-circuiting-assignment-and-and.src.ts | 1 + .../short-circuiting-assignment-or-or.src.ts | 1 + ...uiting-assignment-question-question.src.ts | 1 + packages/types/src/ts-estree.ts | 17 + .../tests/ast-alignment/parse.ts | 15 +- .../semantic-diagnostics-enabled.test.ts.snap | 6 + ...-circuiting-assignment-and-and.src.ts.shot | 170 ++++++++++ ...rt-circuiting-assignment-or-or.src.ts.shot | 170 ++++++++++ ...g-assignment-question-question.src.ts.shot | 170 ++++++++++ 10 files changed, 862 insertions(+), 7 deletions(-) create mode 100644 packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-and-and.src.ts create mode 100644 packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-or-or.src.ts create mode 100644 packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-question-question.src.ts create mode 100644 packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-and-and.src.ts.shot create mode 100644 packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-or-or.src.ts.shot create mode 100644 packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-question-question.src.ts.shot diff --git a/packages/parser/tests/lib/__snapshots__/typescript.ts.snap b/packages/parser/tests/lib/__snapshots__/typescript.ts.snap index 1d7c6fd1725..8fb911f4d4a 100644 --- a/packages/parser/tests/lib/__snapshots__/typescript.ts.snap +++ b/packages/parser/tests/lib/__snapshots__/typescript.ts.snap @@ -31910,6 +31910,324 @@ Object { } `; +exports[`typescript fixtures/basics/short-circuiting-assignment-and-and.src 1`] = ` +Object { + "$id": 3, + "block": Object { + "range": Array [ + 0, + 9, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 2, + "block": Object { + "range": Array [ + 0, + 9, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 0, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + }, + "kind": "rw", + "resolved": null, + "writeExpr": Object { + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + }, + Object { + "$id": 1, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 0, + }, + Object { + "$ref": 1, + }, + ], + "type": "module", + "upperScope": Object { + "$ref": 3, + }, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 2, + }, + "variables": Array [], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [ + Object { + "$ref": 0, + }, + Object { + "$ref": 1, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 3, + }, + "variables": Array [], +} +`; + +exports[`typescript fixtures/basics/short-circuiting-assignment-or-or.src 1`] = ` +Object { + "$id": 3, + "block": Object { + "range": Array [ + 0, + 9, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 2, + "block": Object { + "range": Array [ + 0, + 9, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 0, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + }, + "kind": "rw", + "resolved": null, + "writeExpr": Object { + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + }, + Object { + "$id": 1, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 0, + }, + Object { + "$ref": 1, + }, + ], + "type": "module", + "upperScope": Object { + "$ref": 3, + }, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 2, + }, + "variables": Array [], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [ + Object { + "$ref": 0, + }, + Object { + "$ref": 1, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 3, + }, + "variables": Array [], +} +`; + +exports[`typescript fixtures/basics/short-circuiting-assignment-question-question.src 1`] = ` +Object { + "$id": 3, + "block": Object { + "range": Array [ + 0, + 9, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 2, + "block": Object { + "range": Array [ + 0, + 9, + ], + "type": "Program", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 0, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "a", + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + }, + "kind": "rw", + "resolved": null, + "writeExpr": Object { + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + }, + Object { + "$id": 1, + "from": Object { + "$ref": 2, + }, + "identifier": Object { + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 0, + }, + Object { + "$ref": 1, + }, + ], + "type": "module", + "upperScope": Object { + "$ref": 3, + }, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 2, + }, + "variables": Array [], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [ + Object { + "$ref": 0, + }, + Object { + "$ref": 1, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 3, + }, + "variables": Array [], +} +`; + exports[`typescript fixtures/basics/symbol-type-param.src 1`] = ` Object { "$id": 5, diff --git a/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-and-and.src.ts b/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-and-and.src.ts new file mode 100644 index 00000000000..53c87792bb2 --- /dev/null +++ b/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-and-and.src.ts @@ -0,0 +1 @@ +a ||= b; diff --git a/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-or-or.src.ts b/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-or-or.src.ts new file mode 100644 index 00000000000..2747ba2b3e1 --- /dev/null +++ b/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-or-or.src.ts @@ -0,0 +1 @@ +a &&= b; diff --git a/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-question-question.src.ts b/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-question-question.src.ts new file mode 100644 index 00000000000..eddf7da5264 --- /dev/null +++ b/packages/shared-fixtures/fixtures/typescript/basics/short-circuiting-assignment-question-question.src.ts @@ -0,0 +1 @@ +a ??= b; diff --git a/packages/types/src/ts-estree.ts b/packages/types/src/ts-estree.ts index f268a38257b..b72a1f58b09 100644 --- a/packages/types/src/ts-estree.ts +++ b/packages/types/src/ts-estree.ts @@ -764,6 +764,23 @@ export interface ArrowFunctionExpression extends BaseNode { export interface AssignmentExpression extends BinaryExpressionBase { type: AST_NODE_TYPES.AssignmentExpression; + operator: + | '-=' + | '??=' + | '**=' + | '*=' + | '/=' + | '&&=' + | '&=' + | '%=' + | '^=' + | '+=' + | '<<=' + | '=' + | '>>=' + | '>>>=' + | '|=' + | '||='; } export interface AssignmentPattern extends BaseNode { diff --git a/packages/typescript-estree/tests/ast-alignment/parse.ts b/packages/typescript-estree/tests/ast-alignment/parse.ts index cd9c2db02f8..0e24d6842bd 100644 --- a/packages/typescript-estree/tests/ast-alignment/parse.ts +++ b/packages/typescript-estree/tests/ast-alignment/parse.ts @@ -21,18 +21,19 @@ function createError( function parseWithBabelParser(text: string, jsx = true): any { const babel = require('@babel/parser'); const plugins: ParserPlugin[] = [ - 'typescript', - 'objectRestSpread', - 'decorators-legacy', - 'classProperties', 'asyncGenerators', + 'bigInt', + 'classProperties', + 'decorators-legacy', 'dynamicImport', 'estree', - 'bigInt', - 'numericSeparator', 'importMeta', - 'optionalChaining', + 'logicalAssignment', 'nullishCoalescingOperator', + 'numericSeparator', + 'objectRestSpread', + 'optionalChaining', + 'typescript', ]; if (jsx) { plugins.push('jsx'); diff --git a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.test.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.test.ts.snap index 6b681dda87a..57f10c4a034 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.test.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.test.ts.snap @@ -2038,6 +2038,12 @@ exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" e exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/readonly-tuples.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/short-circuiting-assignment-and-and.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; + +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/short-circuiting-assignment-or-or.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; + +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/short-circuiting-assignment-question-question.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; + exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/symbol-type-param.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/type-alias-declaration.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; diff --git a/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-and-and.src.ts.shot b/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-and-and.src.ts.shot new file mode 100644 index 00000000000..9cc451138fd --- /dev/null +++ b/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-and-and.src.ts.shot @@ -0,0 +1,170 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`typescript basics short-circuiting-assignment-and-and.src 1`] = ` +Object { + "body": Array [ + Object { + "expression": Object { + "left": Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "name": "a", + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "operator": "||=", + "range": Array [ + 0, + 7, + ], + "right": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "type": "AssignmentExpression", + }, + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 8, + ], + "type": "ExpressionStatement", + }, + ], + "comments": Array [], + "loc": Object { + "end": Object { + "column": 0, + "line": 2, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 9, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + "value": "a", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 1, + }, + "start": Object { + "column": 2, + "line": 1, + }, + }, + "range": Array [ + 2, + 5, + ], + "type": "Punctuator", + "value": "||=", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + "value": "b", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 7, + "line": 1, + }, + }, + "range": Array [ + 7, + 8, + ], + "type": "Punctuator", + "value": ";", + }, + ], + "type": "Program", +} +`; diff --git a/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-or-or.src.ts.shot b/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-or-or.src.ts.shot new file mode 100644 index 00000000000..714a7e449b2 --- /dev/null +++ b/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-or-or.src.ts.shot @@ -0,0 +1,170 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`typescript basics short-circuiting-assignment-or-or.src 1`] = ` +Object { + "body": Array [ + Object { + "expression": Object { + "left": Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "name": "a", + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "operator": "&&=", + "range": Array [ + 0, + 7, + ], + "right": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "type": "AssignmentExpression", + }, + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 8, + ], + "type": "ExpressionStatement", + }, + ], + "comments": Array [], + "loc": Object { + "end": Object { + "column": 0, + "line": 2, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 9, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + "value": "a", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 1, + }, + "start": Object { + "column": 2, + "line": 1, + }, + }, + "range": Array [ + 2, + 5, + ], + "type": "Punctuator", + "value": "&&=", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + "value": "b", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 7, + "line": 1, + }, + }, + "range": Array [ + 7, + 8, + ], + "type": "Punctuator", + "value": ";", + }, + ], + "type": "Program", +} +`; diff --git a/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-question-question.src.ts.shot b/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-question-question.src.ts.shot new file mode 100644 index 00000000000..25a13976648 --- /dev/null +++ b/packages/typescript-estree/tests/snapshots/typescript/basics/short-circuiting-assignment-question-question.src.ts.shot @@ -0,0 +1,170 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`typescript basics short-circuiting-assignment-question-question.src 1`] = ` +Object { + "body": Array [ + Object { + "expression": Object { + "left": Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "name": "a", + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "operator": "??=", + "range": Array [ + 0, + 7, + ], + "right": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "name": "b", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "type": "AssignmentExpression", + }, + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 8, + ], + "type": "ExpressionStatement", + }, + ], + "comments": Array [], + "loc": Object { + "end": Object { + "column": 0, + "line": 2, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 9, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 1, + ], + "type": "Identifier", + "value": "a", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 1, + }, + "start": Object { + "column": 2, + "line": 1, + }, + }, + "range": Array [ + 2, + 5, + ], + "type": "Punctuator", + "value": "??=", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + "value": "b", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 7, + "line": 1, + }, + }, + "range": Array [ + 7, + 8, + ], + "type": "Punctuator", + "value": ";", + }, + ], + "type": "Program", +} +`;