Skip to content

Commit

Permalink
Support Async/Await based on #12
Browse files Browse the repository at this point in the history
  • Loading branch information
shirotech committed Apr 10, 2018
1 parent fae708e commit 578a849
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 56 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"semi": [ 2, "always" ],
"keyword-spacing": [ 2, { "before": true, "after": true } ],
"space-before-blocks": [ 2, "always" ],
"space-in-parens": [ 2, "never" ],
"no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ],
"no-cond-assign": [ 0 ]
},
Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ const dangerousTransforms = ['dangerousTaggedTemplateString', 'dangerousForOf'];
export function target(target) {
const targets = Object.keys(target);
let bitmask = targets.length
? 0b11111111111111111111
: 0b01000000000000000000;
? 0b111111111111111111111
: 0b010000000000000000000;

Object.keys(target).forEach(environment => {
const versions = matrix[environment];
Expand Down
47 changes: 47 additions & 0 deletions src/program/BlockStatement.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,53 @@ export default class BlockStatement extends Node {

super.transpile(code, transforms);

if (transforms.asyncAwait && this.isFunctionBlock && this.parent.async && this.body.length) {
const first = this.body[0];
const last = this.body[this.body.length - 1];
const hasOnlyOneLine = this.body.length === 1;

// TODO refactor :)
if (this.parent.type === 'FunctionDeclaration') {
if (hasOnlyOneLine) {
if (first.type === 'ReturnStatement') {
code.insertLeft(first.argument.start, 'Promise.resolve().then(function() { ');
code.insertLeft(first.end, ' })');
} else {
code.insertLeft(first.start, 'return Promise.resolve().then(function() { ');
code.insertRight(last.end, ' }).then(function() {})');
}
} else {
code.insertLeft(first.start, 'return Promise.resolve()');
code.insertRight(last.end, '.then(function() {})');

for (let i = 0; i < this.body.length; i++) {
const prev = this.body[i - 1];
const cur = this.body[i];
const next = this.body[i + 1];

if (cur.expression.type === 'AwaitExpression') {
code.insertLeft(cur.start, '.then(function() { ');
code.insertRight(cur.end, ' })');
} else {
if (!prev || prev.expression.type === 'AwaitExpression') {
code.insertLeft(cur.start, '.then(function() { ');
}

if (!next || next.expression.type === 'AwaitExpression') {
code.insertRight(cur.end, ' })');
}
}
}
}

} else if (this.parent.type === 'ArrowFunctionExpression') {
// TODO merge with ^
// wrap the function's body in a promise
code.insertLeft(first.start + 1, 'Promise.resolve().then(function() { return ');
code.insertLeft(last.end, ' })');
}
}

if (this.createdDeclarations.length) {
introStatementGenerators.push((start, prefix, suffix) => {
const assignment = `${prefix}var ${this.createdDeclarations.join(', ')}${suffix}`;
Expand Down
3 changes: 3 additions & 0 deletions src/program/types/ArrowFunctionExpression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Node from '../Node.js';
import removeTrailingComma from '../../utils/removeTrailingComma.js';
import AwaitExpression from './AwaitExpression';

export default class ArrowFunctionExpression extends Node {
initialise(transforms) {
Expand All @@ -18,6 +19,7 @@ export default class ArrowFunctionExpression extends Node {
}
code.remove(charIndex, this.body.start);

AwaitExpression.removeAsync(code, transforms, this.async, this.start);
super.transpile(code, transforms);

// wrap naked parameter
Expand All @@ -34,6 +36,7 @@ export default class ArrowFunctionExpression extends Node {
code.prependRight(this.start, 'function ');
}
} else {
AwaitExpression.removeAsync(code, transforms, this.async, this.start);
super.transpile(code, transforms);
}

Expand Down
20 changes: 20 additions & 0 deletions src/program/types/AwaitExpression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Node from '../Node.js';

const noop = () => {};

export default class AwaitExpression extends Node {
static removeAsync(code, transforms, async, start, callback = noop) {
if (transforms.asyncAwait && async) {
code.remove(start, start + 6);
callback();
}
}

transpile (code, transforms) {
AwaitExpression.removeAsync(code, transforms, true, this.start, () => {
code.insertLeft(this.argument.start, 'return ');
});

super.transpile(code, transforms);
}
}
2 changes: 2 additions & 0 deletions src/program/types/FunctionDeclaration.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Node from '../Node.js';
import CompileError from '../../utils/CompileError.js';
import removeTrailingComma from '../../utils/removeTrailingComma.js';
import AwaitExpression from './AwaitExpression';

export default class FunctionDeclaration extends Node {
initialise(transforms) {
Expand All @@ -17,6 +18,7 @@ export default class FunctionDeclaration extends Node {
}

transpile(code, transforms) {
AwaitExpression.removeAsync(code, transforms, this.async, this.start);
super.transpile(code, transforms);
if (transforms.trailingFunctionCommas && this.params.length) {
removeTrailingComma(code, this.params[this.params.length - 1].end);
Expand Down
2 changes: 2 additions & 0 deletions src/program/types/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ArrayExpression from './ArrayExpression.js';
import ArrowFunctionExpression from './ArrowFunctionExpression.js';
import AssignmentExpression from './AssignmentExpression.js';
import AwaitExpression from './AwaitExpression.js';
import BinaryExpression from './BinaryExpression.js';
import BreakStatement from './BreakStatement.js';
import CallExpression from './CallExpression.js';
Expand Down Expand Up @@ -50,6 +51,7 @@ export default {
ArrayExpression,
ArrowFunctionExpression,
AssignmentExpression,
AwaitExpression,
BinaryExpression,
BreakStatement,
CallExpression,
Expand Down
109 changes: 55 additions & 54 deletions src/support.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,75 @@
export const matrix = {
chrome: {
48: 0b01001010100011001111,
49: 0b01001111100111111111,
50: 0b01011111100111111111,
51: 0b01011111100111111111,
52: 0b01111111100111111111,
53: 0b01111111100111111111,
54: 0b01111111100111111111,
55: 0b01111111100111111111,
56: 0b01111111100111111111,
57: 0b01111111100111111111,
58: 0b11111111100111111111,
59: 0b11111111100111111111,
60: 0b11111111100111111111,
61: 0b11111111100111111111,
62: 0b11111111100111111111,
63: 0b11111111100111111111
48: 0b010010101000110011101,
49: 0b010011111001111111101,
50: 0b010111111001111111101,
51: 0b010111111001111111101,
52: 0b011111111001111111101,
53: 0b011111111001111111101,
54: 0b011111111001111111101,
55: 0b011111111001111111111,
56: 0b011111111001111111111,
57: 0b011111111001111111111,
58: 0b111111111001111111111,
59: 0b111111111001111111111,
60: 0b111111111001111111111,
61: 0b111111111001111111111,
62: 0b111111111001111111111,
63: 0b111111111001111111111
},
firefox: {
43: 0b01001110100011011101,
44: 0b01001110100111011101,
45: 0b01001110100111011111,
46: 0b01011110100111011111,
47: 0b01011110100111111111,
48: 0b01011110100111111111,
49: 0b01011110100111111111,
50: 0b01011110100111111111,
51: 0b01011110100111111111,
52: 0b11111111100111111111,
53: 0b11111111100111111111,
54: 0b11111111100111111111,
55: 0b11111111100111111111,
56: 0b11111111100111111111,
57: 0b11111111100111111111,
58: 0b11111111100111111111
43: 0b010011101000110111001,
44: 0b010011101001110111001,
45: 0b010011101001110111101,
46: 0b010111101001110111101,
47: 0b010111101001111111101,
48: 0b010111101001111111101,
49: 0b010111101001111111101,
50: 0b010111101001111111101,
51: 0b010111101001111111101,
52: 0b111111111001111111111,
53: 0b111111111001111111111,
54: 0b111111111001111111111,
55: 0b111111111001111111111,
56: 0b111111111001111111111,
57: 0b111111111001111111111,
58: 0b111111111001111111111
},
safari: {
8: 0b01000000000000000100,
9: 0b01001001100001101110,
10: 0b11011111100111111111,
'10.1': 0b11111111100111111111,
11: 0b11111111100111111111
8: 0b010000000000000001000,
9: 0b010010011000011011100,
10: 0b110111111001111111101,
'10.1': 0b111111111001111111111,
11: 0b111111111001111111111
},
ie: {
8: 0b00000000000000000000,
9: 0b01000000000000000000,
10: 0b01000000000000000000,
11: 0b01000000000100000000
8: 0b000000000000000000000,
9: 0b010000000000000000000,
10: 0b010000000000000000000,
11: 0b010000000001000000000
},
edge: {
12: 0b01001010100101001101,
13: 0b01011110100111001111,
14: 0b11111110100111111111,
15: 0b11111110100111111111,
16: 0b11111110100111111111
12: 0b010010101001010011001,
13: 0b010111101001110011101,
14: 0b111111101001111111101,
15: 0b111111101001111111111,
16: 0b111111101001111111111
},
node: {
'0.10': 0b01000000000000000000,
'0.12': 0b01000000000001000000,
4: 0b01001000100011001111,
5: 0b01001000100011001111,
6: 0b01011111100111111111,
8: 0b11111111100111111111,
'8.3': 0b11111111100111111111,
'8.7': 0b11111111100111111111
'0.10': 0b010000000000000000000,
'0.12': 0b010000000000010000000,
4: 0b010010001000110011101,
5: 0b010010001000110011101,
6: 0b010111111001111111101,
8: 0b111111111001111111111,
'8.3': 0b111111111001111111111,
'8.7': 0b111111111001111111111
}
};

export const features = [
'arrow',
'asyncAwait',
'classes',
'computedProperty',
'conciseMethodProperty',
Expand Down
25 changes: 25 additions & 0 deletions test/samples/async-await.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = [
{
description: 'transpiles await arrow function call',
input: `async () => await a()`,
output: `!function() { return Promise.resolve().then(function() { return a() }); }`
},

{
description: 'transpiles await function call',
input: `async function f() { await a(); }`,
output: `function f() { return Promise.resolve().then(function() { return a(); }).then(function() {}) }`
},

{
description: 'transpiles await function call with return statement',
input: `async function f() { return await a(); }`,
output: `function f() { return Promise.resolve().then(function() { return a(); }) }`
},

{
description: 'transpiles await function call with more than one line of code',
input: `async function f() { await a(); thing(); await a2(); stuff(); await a3(); await a4(); }`,
output: `function f() { return Promise.resolve().then(function() { return a(); }) .then(function() { thing(); }) .then(function() { return a2(); }) .then(function() { stuff(); }) .then(function() { return a3(); }) .then(function() { return a4(); }).then(function() {}) }`
}
];

0 comments on commit 578a849

Please sign in to comment.