From 50e0e353ee9237d17a2e244870a8e95748d2d48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Mon, 12 Apr 2021 10:00:42 -0400 Subject: [PATCH] Implement `async-do-expressions` transform (#13117) Co-authored-by: Brian Ng --- .../.npmignore | 3 ++ .../README.md | 19 +++++++ .../package.json | 36 +++++++++++++ .../src/index.ts | 51 +++++++++++++++++++ .../async-do-expressions/basic/exec.js | 4 ++ .../async-do-expressions/basic/input.js | 1 + .../async-do-expressions/basic/output.js | 3 ++ .../empty-statement-list/input.js | 1 + .../empty-statement-list/output.js | 1 + .../exec.js | 6 +++ .../input.js | 1 + .../output.js | 6 +++ .../exec.js | 7 +++ .../input.js | 1 + .../output.js | 7 +++ .../lexical-declaration/exec.js | 4 ++ .../lexical-declaration/input.js | 1 + .../lexical-declaration/output.js | 5 ++ .../throw-statement/exec.js | 5 ++ .../throw-statement/input.js | 1 + .../throw-statement/output.js | 3 ++ .../test/fixtures/options.json | 4 ++ .../sync-do-expressions/basic/input.js | 2 + .../sync-do-expressions/basic/options.json | 4 ++ .../sync-do-expressions/basic/output.js | 2 + .../test/index.js | 3 ++ yarn.lock | 18 ++++++- 27 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 packages/babel-plugin-proposal-async-do-expressions/.npmignore create mode 100644 packages/babel-plugin-proposal-async-do-expressions/README.md create mode 100644 packages/babel-plugin-proposal-async-do-expressions/package.json create mode 100644 packages/babel-plugin-proposal-async-do-expressions/src/index.ts create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/exec.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/input.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/output.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/input.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/output.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/exec.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/input.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/output.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/exec.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/input.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/output.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/exec.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/input.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/output.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/exec.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/input.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/output.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/options.json create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/input.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/options.json create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/output.js create mode 100644 packages/babel-plugin-proposal-async-do-expressions/test/index.js diff --git a/packages/babel-plugin-proposal-async-do-expressions/.npmignore b/packages/babel-plugin-proposal-async-do-expressions/.npmignore new file mode 100644 index 000000000000..f9806945836e --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-proposal-async-do-expressions/README.md b/packages/babel-plugin-proposal-async-do-expressions/README.md new file mode 100644 index 000000000000..89263aec28fb --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/README.md @@ -0,0 +1,19 @@ +# @babel/plugin-proposal-async-do-expressions + +> Transforms async do expressions to ES2021 + +See our website [@babel/plugin-proposal-async-do-expressions](https://babeljs.io/docs/en/babel-plugin-proposal-async-do-expressions) for more information. + +## Install + +Using npm: + +```sh +npm install --save-dev @babel/plugin-proposal-async-do-expressions +``` + +or using yarn: + +```sh +yarn add @babel/plugin-proposal-async-do-expressions --dev +``` diff --git a/packages/babel-plugin-proposal-async-do-expressions/package.json b/packages/babel-plugin-proposal-async-do-expressions/package.json new file mode 100644 index 000000000000..a6742f5fe47f --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/package.json @@ -0,0 +1,36 @@ +{ + "name": "@babel/plugin-proposal-async-do-expressions", + "version": "7.13.11", + "description": "Transform async do expressions to ES2021", + "repository": { + "type": "git", + "url": "https://github.com/babel/babel.git", + "directory": "packages/babel-plugin-proposal-async-do-expressions" + }, + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "main": "./lib/index.js", + "exports": { + ".": "./lib/index.js" + }, + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "@babel/helper-hoist-variables": "workspace:^7.13.0", + "@babel/helper-plugin-utils": "workspace:^7.13.0", + "@babel/plugin-syntax-async-do-expressions": "workspace:^7.13.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + }, + "devDependencies": { + "@babel/core": "workspace:*", + "@babel/helper-plugin-test-runner": "workspace:*", + "@babel/traverse": "workspace:*", + "@babel/types": "workspace:*" + }, + "homepage": "https://babel.dev/docs/en/next/babel-plugin-proposal-async-do-expressions" +} diff --git a/packages/babel-plugin-proposal-async-do-expressions/src/index.ts b/packages/babel-plugin-proposal-async-do-expressions/src/index.ts new file mode 100644 index 000000000000..828630f5758a --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/src/index.ts @@ -0,0 +1,51 @@ +import { declare } from "@babel/helper-plugin-utils"; +import syntaxAsyncDoExpressions from "@babel/plugin-syntax-async-do-expressions"; +import hoistVariables from "@babel/helper-hoist-variables"; +import type * as t from "@babel/types"; +import type { NodePath } from "@babel/traverse"; + +export default declare(({ types: t, assertVersion }) => { + assertVersion("^7.13.0"); + + return { + name: "proposal-async-do-expressions", + inherits: syntaxAsyncDoExpressions, + visitor: { + DoExpression: { + exit(path: NodePath) { + if (!path.is("async")) { + // non-async do expressions are handled by proposal-do-expressions + return; + } + const { scope } = path; + // Hoist variable declaration to containing function scope + // `async do { var x = 1; x }` -> `var x; (async() => { x = 1; return x })()` + hoistVariables( + path, + (id: t.Identifier) => { + scope.push({ id: t.cloneNode(id) }); + }, + "var", + ); + const bodyPath = path.get("body"); + + // add implicit returns to all ending expression statements + const completionRecords = bodyPath.getCompletionRecords(); + + for (const p of completionRecords) { + if (p.isExpressionStatement()) { + p.replaceWith(t.returnStatement(p.node.expression)); + } + } + + path.replaceWith( + t.callExpression( + t.arrowFunctionExpression([], bodyPath.node, /* async */ true), + [], + ), + ); + }, + }, + }, + }; +}); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/exec.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/exec.js new file mode 100644 index 000000000000..308ab692d7f8 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/exec.js @@ -0,0 +1,4 @@ +const x = async do { 21 + 21 }; + +expect(x).toBeInstanceOf(Promise); +x.then((v) => expect(v).toBe(42)).catch(err => { throw err }); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/input.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/input.js new file mode 100644 index 000000000000..b1b52bf4d487 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/input.js @@ -0,0 +1 @@ +const x = async do { 21 + 21 }; diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/output.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/output.js new file mode 100644 index 000000000000..f6709f69c843 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/basic/output.js @@ -0,0 +1,3 @@ +const x = (async () => { + return 21 + 21; +})(); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/input.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/input.js new file mode 100644 index 000000000000..e8f1ba302808 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/input.js @@ -0,0 +1 @@ +async do {} diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/output.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/output.js new file mode 100644 index 000000000000..68b172c0e258 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/empty-statement-list/output.js @@ -0,0 +1 @@ +(async () => {})(); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/exec.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/exec.js new file mode 100644 index 000000000000..ab92ee3ad19e --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/exec.js @@ -0,0 +1,6 @@ +const x = async do { var y = 21; y + y } + +expect(y).toBe(21); +x.then((resolved) => { + expect(resolved).toBe(42); +}).catch(err => { throw err }); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/input.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/input.js new file mode 100644 index 000000000000..59a8221b88b6 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/input.js @@ -0,0 +1 @@ +const x = async do { var y = 21; y + y } diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/output.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/output.js new file mode 100644 index 000000000000..076bb9588515 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assgined-in-sync-context/output.js @@ -0,0 +1,6 @@ +var y; + +const x = (async () => { + y = 21; + return y + y; +})(); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/exec.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/exec.js new file mode 100644 index 000000000000..6af86974f827 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/exec.js @@ -0,0 +1,7 @@ +const x = async do { await Promise.resolve(); var y = 21; y + y } + +expect(y).toBe(undefined); +x.then((resolved) => { + expect(y).toBe(21); + expect(resolved).toBe(42); +}).catch(err => { throw err }); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/input.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/input.js new file mode 100644 index 000000000000..482d369594d3 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/input.js @@ -0,0 +1 @@ +const x = async do { await Promise.resolve(); var y = 21; y + y } diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/output.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/output.js new file mode 100644 index 000000000000..c16ec333a147 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/hoist-variables-assigned-in-async-context/output.js @@ -0,0 +1,7 @@ +var y; + +const x = (async () => { + await Promise.resolve(); + y = 21; + return y + y; +})(); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/exec.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/exec.js new file mode 100644 index 000000000000..f573745d92ac --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/exec.js @@ -0,0 +1,4 @@ +const x = async do { let x = 21; x + x }; + +expect(x).toBeInstanceOf(Promise); +x.then((v) => expect(v).toBe(42)).catch(err => { throw err }); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/input.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/input.js new file mode 100644 index 000000000000..bd969c68d598 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/input.js @@ -0,0 +1 @@ +const x = async do { let x = 21; x + x }; diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/output.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/output.js new file mode 100644 index 000000000000..3b38151981f7 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/lexical-declaration/output.js @@ -0,0 +1,5 @@ +const x = (async () => { + let x = 21; + return x + x; +})(); + diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/exec.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/exec.js new file mode 100644 index 000000000000..7afd19a52e7b --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/exec.js @@ -0,0 +1,5 @@ +const x = async do { throw new Error("sync") }; + +expect(x).toBeInstanceOf(Promise); +x.then(() => { throw new Error("expected an error: sync is thrown.") }) +.catch(err => { expect(err.message).toEqual("sync") }); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/input.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/input.js new file mode 100644 index 000000000000..4864d262f384 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/input.js @@ -0,0 +1 @@ +const x = async do { throw new Error("sync") }; diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/output.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/output.js new file mode 100644 index 000000000000..0ca2644c9a80 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/async-do-expressions/throw-statement/output.js @@ -0,0 +1,3 @@ +const x = (async () => { + throw new Error("sync"); +})(); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/options.json b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/options.json new file mode 100644 index 000000000000..2a430b9d6d4a --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["proposal-async-do-expressions"], + "minNodeVersion": "8.0.0" +} diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/input.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/input.js new file mode 100644 index 000000000000..407b8b2fb3ce --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/input.js @@ -0,0 +1,2 @@ +// sync do expressions are not handled by this plugin +(do {}); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/options.json b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/options.json new file mode 100644 index 000000000000..fd5f2b12380c --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["proposal-async-do-expressions"], + "minNodeVersion": "6.0.0" +} diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/output.js b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/output.js new file mode 100644 index 000000000000..407b8b2fb3ce --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/fixtures/sync-do-expressions/basic/output.js @@ -0,0 +1,2 @@ +// sync do expressions are not handled by this plugin +(do {}); diff --git a/packages/babel-plugin-proposal-async-do-expressions/test/index.js b/packages/babel-plugin-proposal-async-do-expressions/test/index.js new file mode 100644 index 000000000000..21a55ce6b5e7 --- /dev/null +++ b/packages/babel-plugin-proposal-async-do-expressions/test/index.js @@ -0,0 +1,3 @@ +import runner from "@babel/helper-plugin-test-runner"; + +runner(import.meta.url); diff --git a/yarn.lock b/yarn.lock index a4cf916dbcd5..9dbfcdb128ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1021,6 +1021,22 @@ __metadata: languageName: unknown linkType: soft +"@babel/plugin-proposal-async-do-expressions@workspace:packages/babel-plugin-proposal-async-do-expressions": + version: 0.0.0-use.local + resolution: "@babel/plugin-proposal-async-do-expressions@workspace:packages/babel-plugin-proposal-async-do-expressions" + dependencies: + "@babel/core": "workspace:*" + "@babel/helper-hoist-variables": "workspace:^7.13.0" + "@babel/helper-plugin-test-runner": "workspace:*" + "@babel/helper-plugin-utils": "workspace:^7.13.0" + "@babel/plugin-syntax-async-do-expressions": "workspace:^7.13.0" + "@babel/traverse": "workspace:*" + "@babel/types": "workspace:*" + peerDependencies: + "@babel/core": ^7.13.0 + languageName: unknown + linkType: soft + "@babel/plugin-proposal-async-generator-functions@npm:^7.13.15": version: 7.13.15 resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.13.15" @@ -1512,7 +1528,7 @@ __metadata: languageName: unknown linkType: soft -"@babel/plugin-syntax-async-do-expressions@workspace:packages/babel-plugin-syntax-async-do-expressions": +"@babel/plugin-syntax-async-do-expressions@workspace:^7.13.0, @babel/plugin-syntax-async-do-expressions@workspace:packages/babel-plugin-syntax-async-do-expressions": version: 0.0.0-use.local resolution: "@babel/plugin-syntax-async-do-expressions@workspace:packages/babel-plugin-syntax-async-do-expressions" dependencies: