Support optional chaining assignment (#15488)

This commit is contained in:
SUZUKI Sosuke authored and GitHub committed 2023-10-09 08:36:11 +09:00
1 parent c0c3579c29
commit edfe46051f
22 files changed
+576 -64

No files matched your search

+1
View File
@@ -45,6 +45,7 @@ const parseOptions = {
"importReflection",
"explicitResourceManagement",
["importAttributes", { deprecatedAssertSyntax: true }],
["optionalChainingAssign", { version: "2023-07" }],
],
tokens: true,
ranges: true,
@@ -1824,6 +1824,41 @@ const ret = delete obj?.foo?.bar?.baz; // true
================================================================================
`;
exports[`optional-chaining-assignment.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | maybeAnObj?.prop = theValue;
| ^
2 |"
`;
exports[`optional-chaining-assignment.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | maybeAnObj?.prop = theValue;
| ^
2 |"
`;
exports[`optional-chaining-assignment.js [meriyah] format 1`] = `
"Invalid left-hand side in assignment (1:18)
> 1 | maybeAnObj?.prop = theValue;
| ^
2 |"
`;
exports[`optional-chaining-assignment.js format 1`] = `
====================================options=====================================
parsers: ["babel", "babel-ts", "babel-flow"]
printWidth: 80
| printWidth
=====================================input======================================
maybeAnObj?.prop = theValue;
=====================================output=====================================
maybeAnObj?.prop = theValue;
================================================================================
`;
exports[`partial-application.js [acorn] format 1`] = `
"Unexpected token (5:23)
3 | function add(x, y) { return x + y; }
@@ -31,6 +31,7 @@ run_spec(import.meta, ["babel", "babel-ts", "babel-flow"], {
"import-reflection.js",
"explicit-resource-management.js",
"regexp-modifiers.js",
"optional-chaining-assignment.js",
],
espree: [
"decimal.js",
@@ -60,6 +61,7 @@ run_spec(import.meta, ["babel", "babel-ts", "babel-flow"], {
"import-reflection.js",
"explicit-resource-management.js",
"regexp-modifiers.js",
"optional-chaining-assignment.js",
],
meriyah: [
"decimal.js",
@@ -91,6 +93,7 @@ run_spec(import.meta, ["babel", "babel-ts", "babel-flow"], {
"import-reflection.js",
"explicit-resource-management.js",
"regexp-modifiers.js",
"optional-chaining-assignment.js",
],
babel: ["flow.js", "typescript.js"],
__babel_estree: ["flow.js", "typescript.js"],
@@ -0,0 +1 @@
maybeAnObj?.prop = theValue;
@@ -0,0 +1,482 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`invalid-destructuring-arr.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of array destructuring pattern. (1:2)
> 1 | [a?.b] = [];
| ^
2 |"
`;
exports[`invalid-destructuring-arr.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:2)
> 1 | [a?.b] = [];
| ^
2 |"
`;
exports[`invalid-destructuring-arr.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of array destructuring pattern. (1:2)
> 1 | [a?.b] = [];
| ^
2 |"
`;
exports[`invalid-destructuring-arr.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:2)
> 1 | [a?.b] = [];
| ^
2 |"
`;
exports[`invalid-destructuring-arr.js [meriyah] format 1`] = `
"Invalid left-hand side in assignment (1:10)
> 1 | [a?.b] = [];
| ^
2 |"
`;
exports[`invalid-destructuring-obj.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of object destructuring pattern. (1:10)
> 1 | ({ prop: a?.b } = {});
| ^
2 |"
`;
exports[`invalid-destructuring-obj.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:10)
> 1 | ({ prop: a?.b } = {});
| ^
2 |"
`;
exports[`invalid-destructuring-obj.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of object destructuring pattern. (1:10)
> 1 | ({ prop: a?.b } = {});
| ^
2 |"
`;
exports[`invalid-destructuring-obj.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:10)
> 1 | ({ prop: a?.b } = {});
| ^
2 |"
`;
exports[`invalid-destructuring-obj.js [meriyah] format 1`] = `
"Invalid left-hand side in assignment (1:19)
> 1 | ({ prop: a?.b } = {});
| ^
2 |"
`;
exports[`invalid-fn-param.js [__babel_estree] format 1`] = `
"Unexpected token, expected "," (1:13)
> 1 | function f(a?.b) {}
| ^
2 |"
`;
exports[`invalid-fn-param.js [acorn] format 1`] = `
"Unexpected token (1:13)
> 1 | function f(a?.b) {}
| ^
2 |"
`;
exports[`invalid-fn-param.js [babel] format 1`] = `
"Unexpected token, expected "," (1:13)
> 1 | function f(a?.b) {}
| ^
2 |"
`;
exports[`invalid-fn-param.js [espree] format 1`] = `
"Unexpected token ?. (1:13)
> 1 | function f(a?.b) {}
| ^
2 |"
`;
exports[`invalid-fn-param.js [meriyah] format 1`] = `
"Expected ')' (1:14)
> 1 | function f(a?.b) {}
| ^
2 |"
`;
exports[`invalid-fn-param-arrow.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of function parameter list. (1:2)
> 1 | (a?.b) => {}
| ^
2 |"
`;
exports[`invalid-fn-param-arrow.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:2)
> 1 | (a?.b) => {}
| ^
2 |"
`;
exports[`invalid-fn-param-arrow.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of function parameter list. (1:2)
> 1 | (a?.b) => {}
| ^
2 |"
`;
exports[`invalid-fn-param-arrow.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:2)
> 1 | (a?.b) => {}
| ^
2 |"
`;
exports[`invalid-fn-param-arrow.js [meriyah] format 1`] = `
"The left-hand side of the arrow can only be destructed through assignment (1:9)
> 1 | (a?.b) => {}
| ^
2 |"
`;
exports[`invalid-fn-param-assign.js [__babel_estree] format 1`] = `
"Unexpected token, expected "," (1:13)
> 1 | function f(a?.b = c) {}
| ^
2 |"
`;
exports[`invalid-fn-param-assign.js [acorn] format 1`] = `
"Unexpected token (1:13)
> 1 | function f(a?.b = c) {}
| ^
2 |"
`;
exports[`invalid-fn-param-assign.js [babel] format 1`] = `
"Unexpected token, expected "," (1:13)
> 1 | function f(a?.b = c) {}
| ^
2 |"
`;
exports[`invalid-fn-param-assign.js [espree] format 1`] = `
"Unexpected token ?. (1:13)
> 1 | function f(a?.b = c) {}
| ^
2 |"
`;
exports[`invalid-fn-param-assign.js [meriyah] format 1`] = `
"Expected ')' (1:14)
> 1 | function f(a?.b = c) {}
| ^
2 |"
`;
exports[`invalid-for-await-of.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of for-of statement. (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-await-of.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-await-of.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of for-of statement. (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-await-of.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-await-of.js [meriyah] format 1`] = `
"Invalid left-hand side in for-of (1:12)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-in.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of for-in statement. (1:6)
> 1 | for (a?.b in x);
| ^
2 |"
`;
exports[`invalid-for-in.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:6)
> 1 | for (a?.b in x);
| ^
2 |"
`;
exports[`invalid-for-in.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of for-in statement. (1:6)
> 1 | for (a?.b in x);
| ^
2 |"
`;
exports[`invalid-for-in.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:6)
> 1 | for (a?.b in x);
| ^
2 |"
`;
exports[`invalid-for-in.js [meriyah] format 1`] = `
"Invalid left-hand side in for-in (1:12)
> 1 | for (a?.b in x);
| ^
2 |"
`;
exports[`invalid-for-of.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of for-of statement. (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-of.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-of.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of for-of statement. (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-of.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:6)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-for-of.js [meriyah] format 1`] = `
"Invalid left-hand side in for-of (1:12)
> 1 | for (a?.b of x);
| ^
2 |"
`;
exports[`invalid-inc-postfix.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of postfix operation. (1:1)
> 1 | a?.b++;
| ^
2 |"
`;
exports[`invalid-inc-postfix.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | a?.b++;
| ^
2 |"
`;
exports[`invalid-inc-postfix.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of postfix operation. (1:1)
> 1 | a?.b++;
| ^
2 |"
`;
exports[`invalid-inc-postfix.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | a?.b++;
| ^
2 |"
`;
exports[`invalid-inc-postfix.js [meriyah] format 1`] = `
"Invalid increment/decrement operand (1:6)
> 1 | a?.b++;
| ^
2 |"
`;
exports[`invalid-inc-prefix.js [__babel_estree] format 1`] = `
"Invalid optional chaining in the left-hand side of prefix operation. (1:3)
> 1 | ++a?.b;
| ^
2 |"
`;
exports[`invalid-inc-prefix.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:3)
> 1 | ++a?.b;
| ^
2 |"
`;
exports[`invalid-inc-prefix.js [babel] format 1`] = `
"Invalid optional chaining in the left-hand side of prefix operation. (1:3)
> 1 | ++a?.b;
| ^
2 |"
`;
exports[`invalid-inc-prefix.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:3)
> 1 | ++a?.b;
| ^
2 |"
`;
exports[`invalid-inc-prefix.js [meriyah] format 1`] = `
"Invalid increment/decrement operand (1:7)
> 1 | ++a?.b;
| ^
2 |"
`;
exports[`valid-complex-case.js [acorn] format 1`] = `
"The keyword 'let' is reserved (1:1)
> 1 | let?.()[a] =1;
| ^
2 | let?.[a] = 1;
3 |"
`;
exports[`valid-complex-case.js [espree] format 1`] = `
"The keyword 'let' is reserved (1:1)
> 1 | let?.()[a] =1;
| ^
2 | let?.[a] = 1;
3 |"
`;
exports[`valid-complex-case.js [meriyah] format 1`] = `
"\`let\` declaration not allowed here and \`let\` cannot be a regular var name in strict mode (1:5)
> 1 | let?.()[a] =1;
| ^
2 | let?.[a] = 1;
3 |"
`;
exports[`valid-complex-case.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
let?.()[a] =1;
let?.[a] = 1;
=====================================output=====================================
let?.()[a] = 1;
let?.[a] = 1;
================================================================================
`;
exports[`valid-lhs-eq.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | a?.b.c = d;
| ^
2 |"
`;
exports[`valid-lhs-eq.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | a?.b.c = d;
| ^
2 |"
`;
exports[`valid-lhs-eq.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
a?.b.c = d;
=====================================output=====================================
a?.b.c = d;
================================================================================
`;
exports[`valid-lhs-plus-eq.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | a?.b.c += d;
| ^
2 |"
`;
exports[`valid-lhs-plus-eq.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:1)
> 1 | a?.b.c += d;
| ^
2 |"
`;
exports[`valid-lhs-plus-eq.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
a?.b.c += d;
=====================================output=====================================
a?.b.c += d;
================================================================================
`;
exports[`valid-parenthesized.js [acorn] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:2)
> 1 | (a?.b) = c;
| ^
2 |"
`;
exports[`valid-parenthesized.js [espree] format 1`] = `
"Optional chaining cannot appear in left-hand side (1:2)
> 1 | (a?.b) = c;
| ^
2 |"
`;
exports[`valid-parenthesized.js [meriyah] format 1`] = `
"Invalid left-hand side in assignment (1:8)
> 1 | (a?.b) = c;
| ^
2 |"
`;
exports[`valid-parenthesized.js format 1`] = `
====================================options=====================================
parsers: ["babel"]
printWidth: 80
| printWidth
=====================================input======================================
(a?.b) = c;
=====================================output=====================================
a?.b = c;
================================================================================
`;
@@ -0,0 +1 @@
[a?.b] = [];
@@ -0,0 +1 @@
({ prop: a?.b } = {});
@@ -0,0 +1 @@
(a?.b) => {}
@@ -0,0 +1 @@
function f(a?.b = c) {}
@@ -0,0 +1 @@
function f(a?.b) {}
@@ -0,0 +1 @@
for (a?.b of x);
@@ -0,0 +1 @@
for (a?.b in x);
@@ -0,0 +1 @@
for (a?.b of x);
@@ -0,0 +1 @@
a?.b++;
@@ -0,0 +1 @@
++a?.b;
@@ -0,0 +1,37 @@
const invalidSyntaxTests = [
"invalid-destructuring-arr.js",
"invalid-destructuring-obj.js",
"invalid-fn-param-arrow.js",
"invalid-fn-param.js",
"invalid-fn-param-assign.js",
"invalid-for-await-of.js",
"invalid-for-in.js",
"invalid-for-of.js",
"invalid-inc-postfix.js",
"invalid-inc-prefix.js",
];
const optionalChainingAssignTests = [
"valid-lhs-eq.js",
"valid-lhs-plus-eq.js",
"valid-parenthesized.js",
"valid-complex-case.js",
];
// meriyah can parse these files
const meriyahCanParse = new Set(["valid-lhs-eq.js", "valid-lhs-plus-eq.js"]);
run_spec(import.meta, ["babel"], {
errors: {
acorn: [...optionalChainingAssignTests, ...invalidSyntaxTests],
espree: [...optionalChainingAssignTests, ...invalidSyntaxTests],
meriyah: [
...optionalChainingAssignTests.filter(
(test) => !meriyahCanParse.has(test),
),
...invalidSyntaxTests,
],
babel: invalidSyntaxTests,
__babel_estree: invalidSyntaxTests,
},
});
@@ -0,0 +1,2 @@
let?.()[a] =1;
let?.[a] = 1;
@@ -0,0 +1 @@
a?.b.c = d;
@@ -0,0 +1 @@
a?.b.c += d;
@@ -0,0 +1 @@
(a?.b) = c;
@@ -7,12 +7,6 @@ exports[`snippet: #0 [acorn] format 1`] = `
`;
exports[`snippet: #0 [acorn] format 2`] = `
"The keyword 'let' is reserved (1:1)
> 1 | let?.()[a] =1
| ^"
`;
exports[`snippet: #0 [acorn] format 3`] = `
"The keyword 'let' is reserved (1:21)
> 1 | class Foo extends ((let)[0] = 1) {}
| ^"
@@ -24,24 +18,12 @@ exports[`snippet: #0 [babel] format 1`] = `
| ^"
`;
exports[`snippet: #0 [babel] format 2`] = `
"This experimental syntax requires enabling the parser plugin: "optionalChainingAssign". (1:1)
> 1 | let?.()[a] =1
| ^"
`;
exports[`snippet: #0 [babel-ts] format 1`] = `
"Invalid parenthesized assignment pattern. (1:1)
> 1 | ({}) = x;
| ^"
`;
exports[`snippet: #0 [babel-ts] format 2`] = `
"This experimental syntax requires enabling the parser plugin: "optionalChainingAssign". (1:1)
> 1 | let?.()[a] =1
| ^"
`;
exports[`snippet: #0 [espree] format 1`] = `
"Assigning to rvalue (1:1)
> 1 | ({}) = x;
@@ -49,18 +31,12 @@ exports[`snippet: #0 [espree] format 1`] = `
`;
exports[`snippet: #0 [espree] format 2`] = `
"The keyword 'let' is reserved (1:1)
> 1 | let?.()[a] =1
| ^"
`;
exports[`snippet: #0 [espree] format 3`] = `
"The keyword 'let' is reserved (1:21)
> 1 | class Foo extends ((let)[0] = 1) {}
| ^"
`;
exports[`snippet: #0 [espree] format 4`] = `
exports[`snippet: #0 [espree] format 3`] = `
"The keyword 'let' is reserved (1:18)
> 1 | export default ((let)[0] = 1);
| ^"
@@ -83,33 +59,3 @@ exports[`snippet: #0 [meriyah] format 3`] = `
> 1 | export default ((let)[0] = 1);
| ^"
`;
exports[`snippet: #1 [acorn] format 1`] = `
"The keyword 'let' is reserved (1:1)
> 1 | let?.[a] = 1
| ^"
`;
exports[`snippet: #1 [babel] format 1`] = `
"This experimental syntax requires enabling the parser plugin: "optionalChainingAssign". (1:1)
> 1 | let?.[a] = 1
| ^"
`;
exports[`snippet: #1 [babel-ts] format 1`] = `
"This experimental syntax requires enabling the parser plugin: "optionalChainingAssign". (1:1)
> 1 | let?.[a] = 1
| ^"
`;
exports[`snippet: #1 [espree] format 1`] = `
"The keyword 'let' is reserved (1:1)
> 1 | let?.[a] = 1
| ^"
`;
exports[`snippet: #1 [meriyah] format 1`] = `
"\`let\` declaration not allowed here and \`let\` cannot be a regular var name in strict mode (1:5)
> 1 | let?.[a] = 1
| ^"
`;
@@ -1,19 +1,11 @@
run_spec(
{
importMeta: import.meta,
snippets: ["({}) = x;", "let?.[a] = 1"],
snippets: ["({}) = x;"],
},
["babel", "babel-ts", "acorn", "espree", "meriyah"],
);
run_spec(
{
importMeta: import.meta,
snippets: ["let?.()[a] =1"],
},
["babel", "babel-ts", "acorn", "espree"],
);
run_spec(
{
importMeta: import.meta,