Skip to content

Instantly share code, notes, and snippets.

@princejwesley
Last active January 9, 2021 09:20
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save princejwesley/a66d514d86ea174270210561c44b71ba to your computer and use it in GitHub Desktop.
Save princejwesley/a66d514d86ea174270210561c44b71ba to your computer and use it in GitHub Desktop.
REPL with standalone await + babel transform
const repl = require('repl');
const babel = require('babel-core');
function preprocess(input) {
const awaitMatcher = /^(?:\s*(?:(?:let|var|const)\s)?\s*([^=]+)=\s*|^\s*)(await\s[\s\S]*)/;
const asyncWrapper = (code, binder) => {
let assign = binder ? `global.${binder} = ` : '';
return `(function(){ async function _wrap() { return ${assign}${code} } return _wrap();})()`;
};
// match & transform
const match = input.match(awaitMatcher);
if (match) {
input = `${asyncWrapper(match[2], match[1])}`;
}
return input;
}
function myEval(cmd, context, filename, callback) {
const code = babel.transform(preprocess(cmd), {
presets: ['es2015', 'stage-3'],
plugins: [
["transform-runtime", {
"regenerator": true
}]
]
}).code;
_eval(code, context, filename, callback);
}
const replInstance = repl.start({ prompt: '> ' });
const _eval = replInstance.eval;
replInstance.eval = myEval;
@christophemarois
Copy link

christophemarois commented Jan 11, 2017

By running the latest stable node version with the --harmony flag, you can remove the need for babel altogether. Just replace function myEval by:

function myEval(cmd, context, filename, callback) {
  const code = preprocess(cmd);
  _eval(code, context, filename, callback);
}

and run node --harmony await-babel-repl.js

a = await new Promise(res => res(1)) // => 1

Copy link

ghost commented Sep 14, 2017

@christophemarois I installed the latest node (it has native async function support), but it's REPL still does not understand await. Top level await support was never supported by node... I tried with your code and it gives back the promise, it does not wait it out. I tried with this:

const timeout = function (delay) {  
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve()
    }, delay)
  })
}
await Promise.resolve(timeout(3000));

Currently there is a discussion about REPL await support here: nodejs/node#13209 If there is a way to make the REPL hang, then it is possible to implement this. Probably it is possible with a while(1) + break, I'll try it out later.

Can't hang with while(1) because it hangs the event loop and so it does not let the promise to be fulfilled.

function syncAwait(condition, timeout){
	let expirationTime = Date.now() + timeout;
	while(1){
		if (condition())
			return "awaited";
		if (Date.now() > expirationTime)
			return "expired";
	}
}

var i = false;
setTimeout(function (){
	i = true;
}, 2000);

syncAwait(function (){
	return i;
}, 50000);

This returns only expired because the setTimeout can't run until the while loop is finished.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment