Support "Discard Bindings" proposal (#17708)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
fisker Cheungandautofix-ci[bot] authored and GitHub committed 2025-08-04 15:41:42 +08:00
1 parent acd25a9aa6
commit 95ef24d1f0
46 files changed
+3489 -4

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
#### Add support for "Discard Bindings" proposal (#17708 by @fisker)
The Stage 2 proposal ["Discard Bindings"](https://github.com/tc39/proposal-discard-binding) is now supported via Babel. Also keep in mind our [policy on non-standardized syntax](https://prettier.io/docs/en/rationale.html#disclaimer-about-non-standard-syntax) before using this proposed syntax feature with Prettier.
<!-- prettier-ignore -->
```jsx
const [void] = x;
const {x:void} = x;
```
+1
View File
@@ -49,6 +49,7 @@ const parseOptions = {
"sourcePhaseImports",
"deferredImportEvaluation",
["optionalChainingAssign", { version: "2023-07" }],
["discardBinding", { syntaxType: "void" }],
],
tokens: false,
// Ranges not available on comments, so we use `Node#{start,end}` instead
+3
View File
@@ -648,6 +648,9 @@ function printEstree(path, options, print, args) {
case "ModuleExpression":
return ["module ", print("body")];
case "VoidPattern":
return "void";
case "InterpreterDirective": // Printed as comment
default:
/* c8 ignore next */
@@ -66,10 +66,6 @@ const excludeNodeTypes = new Set([
"DecimalLiteral",
// Babel, Won't exist since we use `createImportExpressions` when parsing with babel
"Import",
// Babel v7.28.0
// https://github.com/prettier/prettier/pull/17696
"VoidPattern",
]);
const visitorKeys = Object.fromEntries(
@@ -690,6 +690,51 @@ class Foo {
================================================================================
`;
exports[`discard-binding.js [acorn] format 1`] = `
"Unexpected keyword 'void' (1:11)
> 1 | const [a, void] = iter;
| ^
2 |
Cause: Unexpected keyword 'void' (1:10)"
`;
exports[`discard-binding.js [espree] format 1`] = `
"Unexpected keyword 'void' (1:11)
> 1 | const [a, void] = iter;
| ^
2 |
Cause: Unexpected keyword 'void'"
`;
exports[`discard-binding.js [meriyah] format 1`] = `
"Unexpected token: ']' (1:15)
> 1 | const [a, void] = iter;
| ^
2 |
Cause: [1:14-1:15]: Unexpected token: ']'"
`;
exports[`discard-binding.js [oxc] format 1`] = `
"Identifier expected. 'void' is a reserved word that cannot be used here. (1:11)
> 1 | const [a, void] = iter;
| ^^^^
2 |"
`;
exports[`discard-binding.js format 1`] = `
====================================options=====================================
parsers: ["babel", "babel-ts", "babel-flow"]
printWidth: 80
| printWidth
=====================================input======================================
const [a, void] = iter;
=====================================output=====================================
const [a, void] = iter;
================================================================================
`;
exports[`do-expressions.js [acorn] format 1`] = `
"Unexpected token (3:9)
1 | // https://babeljs.io/docs/babel-plugin-proposal-do-expressions
@@ -0,0 +1 @@
const [a, void] = iter;
@@ -25,6 +25,7 @@ runFormatTest(import.meta, ["babel", "babel-ts", "babel-flow"], {
"source-phase-imports.js",
"deferred-import-evaluation.js",
"optional-chaining-assignment.js",
"discard-binding.js",
],
espree: [
"decorators.js",
@@ -48,6 +49,7 @@ runFormatTest(import.meta, ["babel", "babel-ts", "babel-flow"], {
"source-phase-imports.js",
"deferred-import-evaluation.js",
"optional-chaining-assignment.js",
"discard-binding.js",
],
meriyah: [
"do-expressions.js",
@@ -73,6 +75,7 @@ runFormatTest(import.meta, ["babel", "babel-ts", "babel-flow"], {
"source-phase-imports.js",
"deferred-import-evaluation.js",
"optional-chaining-assignment.js",
"discard-binding.js",
],
oxc: [
"async-do-expressions.js",
@@ -91,6 +94,7 @@ runFormatTest(import.meta, ["babel", "babel-ts", "babel-flow"], {
"throw-expressions.js",
"typescript.js",
"v8intrinsic.js",
"discard-binding.js",
],
"oxc-ts": [
"async-do-expressions.js",
@@ -109,6 +113,7 @@ runFormatTest(import.meta, ["babel", "babel-ts", "babel-flow"], {
"throw-expressions.js",
"typescript.js",
"v8intrinsic.js",
"discard-binding.js",
],
babel: ["flow.js", "typescript.js"],
__babel_estree: ["flow.js", "typescript.js"],
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,36 @@
{
// destructuring binding
const [, void, ] = value;
}
{
// for-of destructuring binding
for (const [void] of []);
}
{
// destructuring assignment
[void] = [];
}
{
// for-of destructuring assignment;
for ([void] of []);
}
{
// function param;
function f([[[void], void, ], void]) {}
}
{
// arrow function param
([[[void], void, ], void]) => {}
}
{
// async arrow function param
async ([[[void], void, ], void]) => {}
}
{
// destructuring assignment in async call";
async([void] = []);
}
{
// catch param
try {} catch ([void]) {}
}
+7
View File
@@ -0,0 +1,7 @@
const [void] = [,void] = [void,] = [];
function f(void, { p: void }, [ void ]) {}
(void, { p: void }, [ void ]) => {}
async (void, { p: void }, [ void ]) => {}
@@ -0,0 +1 @@
(void) => {}
@@ -0,0 +1 @@
([void] = []);
@@ -0,0 +1 @@
async (void) => {}
@@ -0,0 +1 @@
const { p: void } = {};
@@ -0,0 +1,3 @@
async () => {
for(await using void of []);
}
@@ -0,0 +1 @@
for(const { p: void } of []);
@@ -0,0 +1 @@
for({ p: void } of []);
@@ -0,0 +1,3 @@
{
for(using void of []);
}
@@ -0,0 +1,12 @@
runFormatTest(import.meta, ["babel", "flow", "typescript"], {
errors: {
flow: true,
typescript: true,
acorn: true,
espree: true,
meriyah: true,
oxc: true,
"oxc-ts": true,
hermes: true,
},
});
@@ -0,0 +1,20 @@
{
// function parameter
function f(void) {}
}
{
// arrow function parameter
(x, void) => {}
}
{
// async arrow function parameter
async (void, x) => {}
}
{
// object method parameter
({ f(x, void, y) {} });
}
{
// class method parameter
class C { m(void,) {} }
}
@@ -0,0 +1,36 @@
{
// destructuring binding
const { void: void } = value;
}
{
// for-of destructuring binding
for (const { p: void } of []);
}
{
// destructuring assignment
({ p: void } = {});
}
{
// for-of destructuring assignment
for ({ p: void } of []);
}
{
// function param
function f({ q: { q: { p: void }, p: void }, p: void }) {}
}
{
// arrow function param
({ q: { q: { p: void }, p: void }, p: void }) => {}
}
{
// async arrow function param
async ({ q: { q: { p: void }, p: void }, p: void }) => {}
}
{
// destructuring assignment in async call
async({ p: void } = {});
}
{
// catch param
try {} catch ({ p: void }) {}
}
@@ -0,0 +1,16 @@
// expr
void [
// pattern
[ void ] = [{
// expr
[ void [] ]:
// pattern
[ void ] =
// expr
void [
// pattern
([void]) => []
]
// expr
}] = [void []]
]
@@ -0,0 +1,34 @@
{
// using 1 declarator
using void = f();
}
{
// using 2 declarators
using void = f(), void = g();
}
{
// using void declarator and normal declarator
using void = f(), x = g();
}
{
// using declarator in for-of
for(using void of []);
}
async () => {
{
// await using 1 declarator
await using void = f();
}
{
// await using 2 declarators
await using void = f(), void = g();
}
{
// await using void declarator and normal declarator
await using void = f(), x = g();
}
{
// await using declarator in for-of
for(await using void of []);
}
}
+6
View File
@@ -0,0 +1,6 @@
{
using void = f();
}
async (void) => {
await using void = f();
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,10 @@
runFormatTest(import.meta, [
"babel",
"typescript",
"acorn",
"espree",
"meriyah",
"oxc",
"oxc-ts",
"hermes",
]);
@@ -0,0 +1,9 @@
([[[void], x, ], y]);
([[[x], void, ], y]);
([[[x], y, ], void]);
([void, x = 0]);
async([void, x = 0]);
@@ -0,0 +1 @@
void = 0;
@@ -0,0 +1 @@
for (void of []);
@@ -0,0 +1,69 @@
{
// function parameter
function f(void = 0) {}
}
{
// arrow function parameter
(void = 0) => {}
}
{
// async arrow function parameter
async (void = 0) => {}
}
{
// nested array pattern: function parameter
function f([void = 0]) {}
}
{
// nested array pattern: arrow function parameter
([void = 0]) => {}
}
{
// nested array pattern: async arrow function parameter
async ([void = 0]) => {}
}
{
// nested object pattern: function parameter
function f({ p: void = 0 }) {}
}
{
// nested object pattern: arrow function parameter
({ p: void = 0 }) => {}
}
{
// nested object pattern: async arrow function parameter
async ({ p: void = 0 }) => {}
}
{
// nested array pattern: destructuring binding
let [void = 0] = [];
}
{
// nested object pattern: destructuring binding
let { p: void = 0 } = {};
}
{
// nested array pattern: for-of destructuring binding
for (let [void = 0] of []);
}
{
// nested object pattern: for-of destructuring binding
for (let { p: void = 0 } of [{}]);
}
{
// nested array pattern: destructuring assignment
([void = 0] = []);
}
{
// nested object pattern: destructuring assignment
({ p: void = 0 } = {});
}
{
// nested array pattern: for-of destructuring assignment
for ([void = 0] of []);
}
{
// nested object pattern: for-of destructuring assignment
for ({ p: void = 0 } of [{}]);
}
@@ -0,0 +1,5 @@
async(void, x);
async(x, void);
async(void, () => {});
@@ -0,0 +1 @@
try {} catch (void) {}
@@ -0,0 +1,9 @@
({ p: { p: { p: void }, x, }, y});
({ p: { x: { x }, p: void, }, y});
({ y: { x: { x }, y, }, p: void });
({ p: void, x: x = 0 });
async({ p: void, x: x = 0 });
@@ -0,0 +1 @@
[(void)] = [];
@@ -0,0 +1 @@
const [, (void), ] = value;
@@ -0,0 +1 @@
for ([ ...void ] of []);
@@ -0,0 +1 @@
([ ...void ] = []);
@@ -0,0 +1,6 @@
{
var [ ...void ] = [];
}
{
for (var [...void] of [[]]);
}
@@ -0,0 +1 @@
for ({ ...void } of []);
@@ -0,0 +1 @@
({ ...void } = {});
@@ -0,0 +1,6 @@
{
var { ...void } = {};
}
{
for (var { ...void } of [{}]);
}
@@ -0,0 +1,5 @@
(void, x);
(x, void);
(void, () => {});
@@ -0,0 +1,9 @@
{
var void = f();
}
{
let void = f(), void = g();
}
{
const void = f(), x = g();
}
@@ -1170,6 +1170,7 @@ exports[`visitor keys estree 1`] = `
"init",
],
"Variance": [],
"VoidPattern": [],
"VoidTypeAnnotation": [],
"WhileStatement": [
"body",