Socket
Socket
Sign inDemoInstall

async-to-gen

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

async-to-gen - npm Package Compare versions

Comparing version 1.0.6 to 1.1.0

test/test-async-generator.js

218

index.js

@@ -9,5 +9,8 @@ var babylon = require('babylon');

* MagicString has two important functions that can be called: .toString() and
* .generateMap() which returns a source map, as well as a property .isEdited
* which is true when any async functions were transformed.
* .generateMap() which returns a source map, as well as these properties:
*
* - .isEdited: true when any functions were transformed.
* - .containsAsync: true when any async functions were transformed.
* - .containsAsyncGen: true when any async generator functions were transformed.
*
* Options:

@@ -24,2 +27,4 @@ *

editor.isEdited = false;
editor.containsAsync = false;
editor.containsAsyncGen = false;

@@ -47,5 +52,5 @@ // Cheap trick for files that don't actually contain async functions

if (ast.isEdited) {
editor.isEdited = true;
}
editor.isEdited = Boolean(ast.containsAsync || ast.containsAsyncGen);
editor.containsAsync = Boolean(ast.containsAsync);
editor.containsAsyncGen = Boolean(ast.containsAsyncGen);

@@ -85,2 +90,54 @@ return editor;

/**
* A helper function which accepts a generator function and returns an
* Async Iterable based on invoking the generating and resolving an iteration
* of Promises.
*
* Automatically included at the end of files containing async generator
* functions, but also exported from this module for other uses.
* See ./async-node for an example of another usage.
*/
var asyncGenHelper =
'function __asyncGen(g){' +
'var q=[],' +
'T=["next","throw","return"],' +
'I={};' +
'for(var i=0;i<3;i++){' +
'I[T[i]]=a.bind(0,i)' +
'}' +
'Symbol&&(' +
'Symbol.iterator&&(I[Symbol.iterator]=t),' +
'Symbol.asyncIterator&&(I[Symbol.asyncIterator]=t));' +
'function t(){' +
'return this' +
'}' +
'function a(t,v){' +
'return new Promise(function(s,j){' +
'q.push([s,j,v,t]);' +
'q.length===1&&c(v,t)' +
'})' +
'}' +
'function c(v,t){' +
'try{' +
'var r=g[T[t|0]](v),' +
'w=r.value&&r.value.__await;' +
'w?' +
'Promise.resolve(w).then(c,d):' +
'n(r,0)' +
'}catch(e){' +
'n(e,1)' +
'}' +
'}' +
'function d(e){' +
'c(e,1)' +
'}' +
'function n(r,s){' +
'q.shift()[s](r);' +
'q.length&&c(q[0][2],q[0][3])' +
'}' +
'return I' +
'}';
module.exports.asyncGenHelper = asyncGenHelper;
// A collection of methods for each AST type names which contain async functions to

@@ -117,4 +174,9 @@ // be transformed.

leave: function (editor, node, ast) {
if (ast.isEdited && ast.shouldIncludeHelper) {
editor.append('\n' + asyncHelper + '\n');
if (ast.shouldIncludeHelper) {
if (ast.containsAsync) {
editor.append('\n' + asyncHelper + '\n');
}
if (ast.containsAsyncGen) {
editor.append('\n' + asyncGenHelper + '\n');
}
}

@@ -125,3 +187,3 @@ }

enter: function (editor, node, ast) {
var envRecord = ast.scope[ast.scope.length - 1];
var envRecord = currentScope(ast);
if (envRecord.async) {

@@ -132,4 +194,17 @@ envRecord.referencesThis = true;

},
Identifier: {
enter: function (editor, node, ast) {
if (node.name === 'arguments') {
var envRecord = currentScope(ast);
if (envRecord.async) {
envRecord.referencesArgs = true;
}
}
}
},
MemberExpression: {
leave: leaveMemberExpression
},
ForAwaitStatement: {
leave: leaveForAwait
}

@@ -157,4 +232,8 @@ };

// unlike await, yield must not be followed by a new line
if (node.loc.start.line !== node.argument.loc.start.line) {
var envRecord = currentScope(ast);
if (envRecord.generator) {
start += '{__await:';
end += '}';
} else if (node.loc.start.line !== node.argument.loc.start.line) {
// unlike await, yield must not be followed by a new line
start += '(';

@@ -177,3 +256,8 @@ end += ')';

if (node.async) {
ast.isEdited = true;
if (node.generator) {
ast.containsAsyncGen = true;
} else {
ast.containsAsync = true;
}
var idx = findTokenIndex(ast.tokens, node.start);

@@ -185,24 +269,12 @@ while (ast.tokens[idx].value !== 'async') {

var argNames = [];
var argValues = [];
if (node.referencesThis) {
argValues.push('this');
if (node.generator) {
while (ast.tokens[idx].value !== '*') {
idx++;
}
editor.overwrite(ast.tokens[idx].start, ast.tokens[idx + 1].start, ' ');
}
if (node.referencesSuper) {
argNames.push('$uper');
argValues.push('p=>super[p]');
}
if (node.referencesSuperEq) {
argNames.push('$uperEq');
argValues.push('(p,v)=>(super[p]=v)');
}
editor.insertLeft(
node.body.start + 1,
'return __async(function*(' + argNames.join(',') + '){'
);
editor.insertRight(
node.body.end - 1,
(node.referencesThis ? '}.call(' : '}(') + argValues.join(',') + '))'
);
var wrapping = createAsyncWrapping(node);
editor.insertLeft(node.body.start + 1, 'return ' + wrapping[0]);
editor.insertRight(node.body.end - 1, wrapping[1]);
}

@@ -219,17 +291,21 @@ }

if (node.async) {
if (node.generator) {
ast.containsAsyncGen = true;
} else {
ast.containsAsync = true;
}
ast.scope.pop();
if (node.referencesThis) {
ast.scope[ast.scope.length - 1].referencesThis = true;
}
if (node.referencesSuper) {
ast.scope[ast.scope.length - 1].referencesSuper = true;
}
if (node.referencesSuperEq) {
ast.scope[ast.scope.length - 1].referencesSuperEq = true;
}
ast.isEdited = true;
var envRecord = currentScope(ast);
envRecord.referencesThis |= node.referencesThis;
envRecord.referencesArgs |= node.referencesArgs;
envRecord.referencesSuper |= node.referencesSuper;
envRecord.referencesSuperEq |= node.referencesSuperEq;
var wrapping = createAsyncWrapping(node);
editor.remove(node.start, node.start + 6);
if (node.body.type === 'BlockStatement') {
editor.overwrite(node.body.start, node.body.start + 1, '__async(function*(){');
editor.overwrite(node.body.end - 1, node.body.end, node.referencesThis ? '}.call(this))' : '}())');
editor.overwrite(node.body.start, node.body.start + 1, wrapping[0]);
editor.overwrite(node.body.end - 1, node.body.end, wrapping[1]);
} else {

@@ -240,5 +316,5 @@ var idx = findTokenIndex(ast.tokens, node.body.start) - 1;

}
editor.insertRight(ast.tokens[idx].end, '__async(function*(){');
editor.insertRight(ast.tokens[idx].end, wrapping[0]);
editor.insertLeft(node.body.start, 'return ');
editor.insertRight(node.body.end, node.referencesThis ? '}.call(this))' : '}())');
editor.insertRight(node.body.end, wrapping[1]);
}

@@ -248,2 +324,35 @@ }

function createAsyncWrapping(node) {
var argNames = [];
var argValues = [];
if (node.referencesThis) {
argValues.push('this');
}
if (node.referencesArgs) {
argNames.push('arguments');
argValues.push('arguments');
}
if (node.type !== 'ArrowFunctionExpression') {
if (node.referencesSuper) {
argNames.push('$uper');
argValues.push('p=>super[p]');
}
if (node.referencesSuperEq) {
argNames.push('$uperEq');
argValues.push('(p,v)=>(super[p]=v)');
}
}
var helperName = node.generator ? '__asyncGen' : '__async';
return [
helperName + '(function*(' + argNames.join(',') + '){',
(node.referencesThis ? '}.call(' : '}(') + argValues.join(',') + '))'
];
}
function leaveMemberExpression(editor, node, ast, stack) {

@@ -254,3 +363,3 @@ // Only transform super member expressions.

// Only within transformed async function scopes.
var envRecord = ast.scope[ast.scope.length - 1];
var envRecord = currentScope(ast);
if (!envRecord.async) return;

@@ -304,2 +413,19 @@

function leaveForAwait(editor, node, ast) {
var idx = findTokenIndex(ast.tokens, node.start) + 1;
while (ast.tokens[idx].value !== 'await') {
idx++;
}
editor.remove(ast.tokens[idx].start, ast.tokens[idx + 1].start);
var tmpName = '$await' + (ast.scope.length - 1);
editor.move(node.left.start, node.left.end, node.body.start + 1);
editor.insertLeft(node.left.end, '=yield{__await:' + tmpName + '};');
editor.insertLeft(node.left.start, 'let ' + tmpName);
}
function currentScope(ast) {
return ast.scope[ast.scope.length - 1];
}
// Given the AST output of babylon parse, walk through in a depth-first order,

@@ -306,0 +432,0 @@ // calling methods on the given visitor, providing editor as the first argument.

{
"name": "async-to-gen",
"version": "1.0.6",
"version": "1.1.0",
"description": "Transform async functions to generator functions with speed and simplicity.",

@@ -21,3 +21,3 @@ "author": "Lee Byron <lee@leebyron.com> (http://leebyron.com/)",

"scripts": {
"test": "DIFF=$(./async-to-gen test/source.js | diff test/expected.js -); if [ -n \"$DIFF\" ]; then echo \"$DIFF\"; exit 1; fi; RES=$(node -e 'require(\"./register\");require(\"./test/test-node-module.js\")'); if [ \"$RES\" != 42 ]; then echo 'Node register hook failed'; exit 1; fi; ASYNC_NODE=$(./async-node ./test/test-node-module.js); if [ \"$ASYNC_NODE\" != 42 ]; then echo 'async-node failed'; exit 1; fi;",
"test": "DIFF=$(./async-to-gen test/source.js | diff test/expected.js -); if [ -n \"$DIFF\" ]; then echo \"$DIFF\"; exit 1; fi; RES=$(node -e 'require(\"./register\");require(\"./test/test-node-module.js\")'); if [ \"$RES\" != 42 ]; then echo 'Node register hook failed'; exit 1; fi; ASYNC_NODE=$(./async-node ./test/test-node-module.js); if [ \"$ASYNC_NODE\" != 42 ]; then echo 'async-node failed'; exit 1; fi; ASYNC_GEN_NODE=$(./async-node ./test/test-async-generator.js); if [ \"$ASYNC_GEN_NODE\" != 42 ]; then echo 'async-node failed for async generators'; exit 1; fi;",
"test-update": "./async-to-gen test/source.js > test/expected.js"

@@ -24,0 +24,0 @@ },

@@ -19,3 +19,7 @@ async-to-gen

Also, `async-to-gen` provides support for [async generators](https://github.com/tc39/proposal-async-iteration)
which return Async Iterators, a great syntax and primitive for producing and
operating on streams of data.
## Get Started!

@@ -183,3 +187,46 @@

#### Streams
Streaming data can be a challenging thing to get right. While [Observables](http://reactivex.io/documentation/observable.html) have provided a great library for
streamed data, Async Generators provides language-level support for this concept!
Consider subscribing to a web socket within an program using async functions:
```js
async function* stockTickerInEuro(symbol) {
var socket = await openWebSocket('ws://stocks.com/' + symbol)
try {
for await (var usd of socket) {
var euro = usd * await loadExchangeRateUSD2EUR()
yield euro
}
} finally {
closeWebSocket(socket)
}
}
```
Then calling this function produces an Async Iterator (an Iterator of Promises)
of stock ticker values.
```js
var ticker = stockTickerInEuro('AAPL')
ticker.next().then(step => console.log(step.value))
```
Or use `for-await` loops within another async function:
```js
async function bloombergTerminal() {
for await (var price of stockTickerInEuro('AAPL')) {
console.log(price)
}
}
```
NOTE: The behavior of `for-await` loops using this tool is not identical to the
proposed spec addition. Where the proposed spec's `for-await` expects a
`Symbol.asyncIterator` method for the iterated source, this tool expects
`Symbol.iterator` instead since it transforms it to a `for-of` loop.
## Dead-Simple Transforms

@@ -191,4 +238,4 @@

It also includes a very small (217 character) conversion function at the bottom
of the file.
It also includes a very small conversion function at the bottom of the file.
How small? 217 chars for async functions and 533 chars for async generators.

@@ -195,0 +242,0 @@ **Before:**

@@ -13,2 +13,12 @@ "use strict"

// async gen function statement
function foo() {return __asyncGen(function*(){
yield yield{__await: x}
}())}
// async gen function expression
var bar = function () {return __asyncGen(function*(){
yield{__await: (yield x)}
}())}
// async arrow functions with body

@@ -27,2 +37,6 @@ var arrow1 = () => __async(function*(){

yield this.x
}.call(this))},
bazGen() {return __asyncGen(function*(){
yield yield{__await: this.x}
}.call(this))}

@@ -36,2 +50,6 @@ }

}.call(this))}
woofGen() {return __asyncGen(function*(){
yield{__await: (yield this.x)};
}.call(this))}
}

@@ -44,2 +62,6 @@

}.call(this))}
static woofGen() {return __asyncGen(function*(){
yield yield{__await: this.x};
}.call(this))}
}

@@ -98,2 +120,18 @@

// normal function referencing arguments
function normalThis() {
return arguments;
}
// async function referencing arguments
function asyncThis() {return __async(function*(arguments){
return arguments;
}(arguments))}
// async arrow function referencing arguments
function within1() {return __async(function*(arguments){
() => () =>__async(function*(arguments){ return arguments}(arguments))
}(arguments))}
class SuperDuper extends BaseClass {

@@ -169,2 +207,17 @@ constructor(arg) {

// await gen on its own line
function ownLineGen() {return __asyncGen(function*(){
yield{__await:
someThing};
}())}
// for await
function mapStream(stream, mapper) {return __asyncGen(function*(){
for (let $await1 of stream) {let item=yield{__await:$await1};
yield yield{__await: mapper(item)};
}
}())}
function __async(g){return new Promise(function(s,j){function c(a,x){try{var r=g[x?"throw":"next"](a)}catch(e){return j(e)}return r.done?s(r.value):Promise.resolve(r.value).then(c,d)}function d(e){return c(e,1)}c()})}
function __asyncGen(g){var q=[],T=["next","throw","return"],I={};for(var i=0;i<3;i++){I[T[i]]=a.bind(0,i)}Symbol&&(Symbol.iterator&&(I[Symbol.iterator]=t),Symbol.asyncIterator&&(I[Symbol.asyncIterator]=t));function t(){return this}function a(t,v){return new Promise(function(s,j){q.push([s,j,v,t]);q.length===1&&c(v,t)})}function c(v,t){try{var r=g[T[t|0]](v),w=r.value&&r.value.__await;w?Promise.resolve(w).then(c,d):n(r,0)}catch(e){n(e,1)}}function d(e){c(e,1)}function n(r,s){q.shift()[s](r);q.length&&c(q[0][2],q[0][3])}return I}

@@ -13,2 +13,12 @@ "use strict"

// async gen function statement
async function* foo() {
yield await x
}
// async gen function expression
var bar = async function* () {
await (yield x)
}
// async arrow functions with body

@@ -27,2 +37,6 @@ var arrow1 = async () => {

await this.x
},
async* bazGen() {
yield await this.x
}

@@ -36,2 +50,6 @@ }

}
async* woofGen() {
await (yield this.x);
}
}

@@ -44,2 +62,6 @@

}
static async* woofGen() {
yield await this.x;
}
}

@@ -98,2 +120,18 @@

// normal function referencing arguments
function normalThis() {
return arguments;
}
// async function referencing arguments
async function asyncThis() {
return arguments;
}
// async arrow function referencing arguments
async function within1() {
() => async () => arguments
}
class SuperDuper extends BaseClass {

@@ -168,1 +206,14 @@ constructor(arg) {

}
// await gen on its own line
async function* ownLineGen() {
await
someThing;
}
// for await
async function* mapStream(stream, mapper) {
for await (let item of stream) {
yield await mapper(item);
}
}

@@ -8,3 +8,3 @@ // @flow

await
42 :
arguments[0] :
await

@@ -17,2 +17,2 @@ 99

genAnswer().then(function (val) { console.log(val) });
genAnswer(42).then(function (val) { console.log(val) });

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc