Skip to content
This repository has been archived by the owner on May 5, 2023. It is now read-only.

Commit

Permalink
Drop co, make non-Promises yieldable
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate committed Oct 18, 2019
1 parent 66eb9ad commit b22b58f
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 5 deletions.
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@
"license": "MIT",
"dependencies": {
"ast-types": "^0.13.2",
"co": "^4.6.0",
"escodegen": "^1.8.1",
"esprima": "^4.0.0"
},
"devDependencies": {
"@types/co": "^4.6.2",
"@types/escodegen": "^0.0.6",
"@types/esprima": "^4.0.2",
"@types/mocha": "^5.2.7",
Expand Down
61 changes: 61 additions & 0 deletions src/generator-to-promise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
interface Deferred<T> {
promise: Promise<T>;
resolve: (value?: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
}

function isGen(fn: any): fn is GeneratorFunction {
return (
typeof fn == 'function' && fn.constructor.name == 'GeneratorFunction'
);
}

function createDeferred<T>(): Deferred<T> {
let r;
let j;
const promise = new Promise<T>(
(
resolve: (value?: T | PromiseLike<T>) => void,
reject: (reason?: any) => void
): void => {
r = resolve;
j = reject;
}
);
if (!r || !j) {
throw new Error('Creating Deferred failed');
}
return { promise, resolve: r, reject: j };
}

export default function generatorToPromise<T>(
generatorFunction: any
): (...args: any[]) => Promise<T> {
if (!isGen(generatorFunction)) {
throw new Error('The given function must be a generator function');
}

return function invoker(this: any) {
const deferred = createDeferred<T>();
const generator = generatorFunction.call(this, arguments);
(function next(error?: Error | null, value?: any) {
let genState = null;
try {
if (error) genState = generator.throw(error);
else genState = generator.next(value);
} catch (e) {
genState = { value: Promise.reject(e), done: true };
}

if (genState.done) {
deferred.resolve(genState.value);
} else {
Promise.resolve(genState.value)
.then(promiseResult => next(null, promiseResult))
.catch(error => next(error));
}
})();

return deferred.promise;
};
}
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { wrap } from 'co';
import { isRegExp } from 'util';
import { generate } from 'escodegen';
import { parseScript } from 'esprima';
import { visit, namedTypes as n, builders as b } from 'ast-types';
import { Context, RunningScriptOptions, runInNewContext } from 'vm';

import supportsAsync from './supports-async';
import generatorToPromise from './generator-to-promise';

/**
* Turns sync JavaScript code into an JavaScript with async Functions.
Expand Down Expand Up @@ -165,7 +166,7 @@ namespace degenerator {
if (supportsAsync) {
return fn as T;
} else {
return (wrap(fn) as unknown) as T;
return (generatorToPromise(fn) as unknown) as T;
}
}
}
Expand Down
21 changes: 20 additions & 1 deletion test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,26 @@ describe('degenerator()', () => {
fn().then((val: string) => {
assert.equal(val, 'ab');
done();
});
}, done);
});
it('should be able to await non-promises', done => {
const a = () => 'a';
const b = () => 'b';
function aPlusB(): string {
return a() + b();
}
const fn = compile<() => Promise<string>>(
'' + aPlusB,
'aPlusB',
['a'],
{
sandbox: { a, b }
}
);
fn().then((val: string) => {
assert.equal(val, 'ab');
done();
}, done);
});
});
});

0 comments on commit b22b58f

Please sign in to comment.