Skip to content

Commit

Permalink
Allow async .pre and .post
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Sep 28, 2019
1 parent 0da4f7e commit 3f640b2
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 31 deletions.
28 changes: 28 additions & 0 deletions packages/babel-core/src/gensync-utils/maybe-async.js
@@ -0,0 +1,28 @@
// @flow

import gensync, { type Gensync } from "gensync";

export default function maybeAsync<T, Args: any[]>(
fn: (...args: Args) => T,
message: string,
): Gensync<Args, T> {
return gensync({
sync(...args) {
const result = fn.apply(this, args);
if (isThenable(result)) throw new Error(message);
return result;
},
async(...args) {
return Promise.resolve(fn.apply(this, args));
},
});
}

function isThenable(val: mixed): boolean {
return (
!!val &&
(typeof val === "object" || typeof val === "function") &&
!!val.then &&
typeof val.then === "function"
);
}
43 changes: 12 additions & 31 deletions packages/babel-core/src/transformation/index.js
Expand Up @@ -3,6 +3,8 @@ import traverse from "@babel/traverse";
import typeof { SourceMap } from "convert-source-map";
import type { Handler } from "gensync";

import maybeAsync from "../gensync-utils/maybe-async";

import type { ResolvedConfig, PluginPasses } from "../config";

import PluginPass from "./plugin-pass";
Expand Down Expand Up @@ -72,17 +74,11 @@ function* transformFile(file: File, pluginPasses: PluginPasses): Handler<void> {
for (const [plugin, pass] of passPairs) {
const fn = plugin.pre;
if (fn) {
const result = fn.call(pass, file);

// ASYNC, if we want to allow async .pre
if (isThenable(result)) {
throw new Error(
`You appear to be using an plugin with an async .pre, ` +
`which your current version of Babel does not support. ` +
`If you're using a published plugin, you may need to upgrade ` +
`your @babel/core version.`,
);
}
yield* maybeAsync(
fn,
`You appear to be using an plugin with an async .pre, ` +
`but Babel has been called synchronously.`,
).call(pass, file);
}
}

Expand All @@ -97,27 +93,12 @@ function* transformFile(file: File, pluginPasses: PluginPasses): Handler<void> {
for (const [plugin, pass] of passPairs) {
const fn = plugin.post;
if (fn) {
const result = fn.call(pass, file);

// ASYNC, if we want to allow async .post
if (isThenable(result)) {
throw new Error(
`You appear to be using an plugin with an async .post, ` +
`which your current version of Babel does not support. ` +
`If you're using a published plugin, you may need to upgrade ` +
`your @babel/core version.`,
);
}
yield* maybeAsync(
fn,
`You appear to be using an plugin with an async .post, ` +
`but Babel has been called synchronously.`,
).call(pass, file);
}
}
}
}

function isThenable(val: mixed): boolean {
return (
!!val &&
(typeof val === "object" || typeof val === "function") &&
!!val.then &&
typeof val.then === "function"
);
}
@@ -0,0 +1,15 @@
const wait = t => new Promise(res => setTimeout(res, t));

const code = "function f() {}";

transform(code, {
plugins: [
function() {
return {
async pre() {
await wait(50);
}
}
}
]
});
@@ -0,0 +1,3 @@
{
"throws": "You appear to be using an plugin with an async .pre, but Babel has been called synchronously."
}
15 changes: 15 additions & 0 deletions packages/babel-core/test/fixtures/plugins/async-pre/exec.js
@@ -0,0 +1,15 @@
const wait = t => new Promise(res => setTimeout(res, t));

const code = "function f() {}";

transform(code, {
plugins: [
function() {
return {
async pre() {
await wait(50);
}
}
}
]
}, (err, res) => {});

0 comments on commit 3f640b2

Please sign in to comment.