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

Commit

Permalink
Fix nested yield statements
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate committed Feb 5, 2020
1 parent 9c8d43a commit d41a91d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 28 deletions.
58 changes: 35 additions & 23 deletions src/generator-to-promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ interface Deferred<T> {
reject: (reason?: any) => void;
}

function isGen(fn: any): fn is GeneratorFunction {
function isGenerator(fn: any): fn is Generator {
return fn && fn.next && fn.throw;
}

function isGeneratorFunction(fn: any): fn is GeneratorFunction {
return (
typeof fn == 'function' && fn.constructor.name == 'GeneratorFunction'
);
Expand All @@ -28,10 +32,10 @@ function createDeferred<T>(): Deferred<T> {
return { promise, resolve: r, reject: j };
}

export default function generatorToPromise<T>(
export default function generatorFnToPromise<T>(
generatorFunction: any
): (...args: any[]) => Promise<T> {
if (!isGen(generatorFunction)) {
if (!isGeneratorFunction(generatorFunction)) {
if (typeof generatorFunction === 'function') {
return function(this: any, ...args: any[]) {
return Promise.resolve(true).then(() => {
Expand All @@ -43,29 +47,37 @@ export default function generatorToPromise<T>(
}

return function(this: any, ...args: any[]): Promise<T> {
const deferred = createDeferred<T>();
const generator = generatorFunction.apply(this, args);
(function next(err?: Error | null, value?: any) {
let genState = null;
try {
if (err) {
genState = generator.throw(err);
} else {
genState = generator.next(value);
}
} catch (e) {
genState = { value: Promise.reject(e), done: true };
}
return generatorToPromise(generator);
};
}

if (genState.done) {
deferred.resolve(genState.value);
function generatorToPromise<T>(this: any, generator: any): Promise<T> {
const deferred = createDeferred<T>();
(function next(err?: Error | null, value?: any) {
let genState = null;
try {
if (err) {
genState = generator.throw(err);
} else {
Promise.resolve(genState.value)
.then(promiseResult => next(null, promiseResult))
.catch(err => next(err));
genState = generator.next(value);
}
})();
} catch (e) {
genState = { value: Promise.reject(e), done: true };
}

return deferred.promise;
};
if (isGenerator(genState.value)) {
genState.value = generatorToPromise(genState.value);
}

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

return deferred.promise;
}
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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';
import generatorToPromiseFn from './generator-to-promise';

/**
* Compiles sync JavaScript code into JavaScript with async Functions.
Expand Down Expand Up @@ -174,11 +174,11 @@ namespace degenerator {
if (isAsyncFunction(fn)) {
return fn;
} else {
const rtn = (generatorToPromise(fn) as unknown) as T;
const rtn = (generatorToPromiseFn(fn) as unknown) as T;
Object.defineProperty(rtn, 'toString', {
value: fn.toString.bind(fn),
enumerable: false
})
});
return rtn;
}
}
Expand Down
30 changes: 28 additions & 2 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ describe('degenerator()', () => {
}
);
if (supportsAsync) {
assert(/await b\(\)/.test(fn+''));
assert(/await b\(\)/.test(fn + ''));
} else {
assert(/yield b\(\)/.test(fn+''));
assert(/yield b\(\)/.test(fn + ''));
}
});
it('should be able to await non-promises', () => {
Expand Down Expand Up @@ -188,5 +188,31 @@ describe('degenerator()', () => {
'Expected a "function" to be returned for `foo`, but got "number"'
);
});
it('should be compile if branches', () => {
function ifA(): string {
if (a()) {
return 'foo';
}
return 'bar';
}
function a() {
if (b()) {
return false;
}
return true;
}
function b() {
return false;
}
const fn = compile<() => Promise<string>>(
`${ifA};${a}`,
'ifA',
['b'],
{ sandbox: { b } }
);
return fn().then((val: string) => {
assert.equal(val, 'foo');
});
});
});
});

0 comments on commit d41a91d

Please sign in to comment.