You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
591 lines
14 KiB
JavaScript
591 lines
14 KiB
JavaScript
6 years ago
|
'use strict';
|
||
|
|
||
|
var acorn = require('acorn');
|
||
|
require('../')(acorn);
|
||
|
var estraverse = require('estraverse');
|
||
|
var xtend = require('xtend');
|
||
|
var assert = require('assert');
|
||
|
|
||
|
function find (type, ast, skip) {
|
||
|
skip = skip || 0;
|
||
|
var skipped = 0;
|
||
|
|
||
|
var found;
|
||
|
|
||
|
estraverse.traverse(ast, {
|
||
|
enter: (node) => {
|
||
|
if (found) {
|
||
|
return estraverse.VisitorOption.Skip;
|
||
|
}
|
||
|
if (node.type == type) {
|
||
|
if (skipped === skip) {
|
||
|
found = node;
|
||
|
return estraverse.VisitorOption.Skip;
|
||
|
}
|
||
|
skipped++;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (!found) {
|
||
|
throw new Error('did not find AwaitExpression (skipped ' + skipped + '/' + skip + ')');
|
||
|
}
|
||
|
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
function extendOptions(pluginOptions, acornOptions) {
|
||
|
return xtend({
|
||
|
sourceType: 'module',
|
||
|
ecmaVersion: 8,
|
||
|
locations: true,
|
||
|
ranges: true,
|
||
|
plugins: {asyncawait: pluginOptions || pluginOptions !== false}
|
||
|
}, acornOptions);
|
||
|
}
|
||
|
|
||
|
function parse(code, pluginOptions, acornOptions) {
|
||
|
if (Array.isArray(code)) {
|
||
|
code = code.join('\n');
|
||
|
}
|
||
|
var options = extendOptions(pluginOptions, acornOptions);
|
||
|
return acorn.parse(code, options);
|
||
|
}
|
||
|
|
||
|
describe('async', () => {
|
||
|
describe ('function declaration', () => {
|
||
|
var node;
|
||
|
|
||
|
describe('-', () => {
|
||
|
beforeEach(() => {
|
||
|
node = find(
|
||
|
'FunctionDeclaration',
|
||
|
parse([
|
||
|
'async function foo() {',
|
||
|
' x = await bar()',
|
||
|
'}'
|
||
|
])
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('marks the node as async', () =>
|
||
|
assert(node.async)
|
||
|
);
|
||
|
|
||
|
it('finds correct start position', () =>
|
||
|
assert.strictEqual(node.start, 0)
|
||
|
);
|
||
|
|
||
|
it('finds correct end position', () =>
|
||
|
assert.strictEqual(node.end, 42)
|
||
|
);
|
||
|
|
||
|
it('finds correct start line/column', () =>
|
||
|
assert.deepEqual(node.loc.start, {
|
||
|
line: 1,
|
||
|
column: 0
|
||
|
})
|
||
|
);
|
||
|
|
||
|
it('finds correct end line/column', () =>
|
||
|
assert.deepEqual(node.loc.end, {
|
||
|
line: 3,
|
||
|
column: 1
|
||
|
})
|
||
|
);
|
||
|
});
|
||
|
|
||
|
var assertFindsIdentifierExpressionStatement = (ast) => {
|
||
|
node = find('ExpressionStatement', ast);
|
||
|
assert.strictEqual(node.expression.type, 'Identifier');
|
||
|
assert.strictEqual(node.expression.name, 'async');
|
||
|
assert.deepEqual(node.expression.loc, {
|
||
|
start: {
|
||
|
line: 1,
|
||
|
column: 0
|
||
|
},
|
||
|
end: {
|
||
|
line: 1,
|
||
|
column: 5
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
describe('linefeed after async (simple)', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'async \t\t ',
|
||
|
'function foo() {',
|
||
|
'}'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('finds Identifier ExpressionStatement', () => {
|
||
|
assertFindsIdentifierExpressionStatement(ast);
|
||
|
});
|
||
|
|
||
|
it('does not mark FunctionDeclaration as async', () => {
|
||
|
node = find('FunctionDeclaration', ast);
|
||
|
assert(!node.async, 'Expected node.async to be false');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (single line comment)', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'async // flag enables async completion',
|
||
|
'function foo() {',
|
||
|
'}'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('finds Identifier ExpressionStatement', () => {
|
||
|
assertFindsIdentifierExpressionStatement(ast);
|
||
|
});
|
||
|
|
||
|
it('does not mark FunctionDeclaration as async', () => {
|
||
|
node = find('FunctionDeclaration', ast);
|
||
|
assert(!node.async, 'Expected node.async to be false');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (multiline comment) function', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'async /* flag enables async completion',
|
||
|
' of the callback */function foo() {',
|
||
|
'}'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('finds Identifier ExpressionStatement', () => {
|
||
|
assertFindsIdentifierExpressionStatement(ast);
|
||
|
});
|
||
|
|
||
|
it('does not mark FunctionDeclaration as async', () => {
|
||
|
node = find('FunctionDeclaration', ast);
|
||
|
assert(!node.async, 'Expected node.async to be false');
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe ('function expression', () => {
|
||
|
var node, code;
|
||
|
|
||
|
describe('-', () => {
|
||
|
beforeEach(() => {
|
||
|
code = [
|
||
|
'foo = async function () {',
|
||
|
' x = await bar()',
|
||
|
'}'
|
||
|
];
|
||
|
node = find(
|
||
|
'FunctionExpression',
|
||
|
parse(code)
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('marks the node as async', () =>
|
||
|
assert(node.async)
|
||
|
);
|
||
|
|
||
|
it('finds correct start position', () =>
|
||
|
assert.strictEqual(node.start, 6)
|
||
|
);
|
||
|
|
||
|
it('finds correct end position', () =>
|
||
|
assert.strictEqual(node.end, code.join('\n').length)
|
||
|
);
|
||
|
|
||
|
it('finds correct start line/column', () =>
|
||
|
assert.deepEqual(node.loc.start, {
|
||
|
line: 1,
|
||
|
column: 6
|
||
|
})
|
||
|
);
|
||
|
|
||
|
it('finds correct end line/column', () =>
|
||
|
assert.deepEqual(node.loc.end, {
|
||
|
line: 3,
|
||
|
column: 1
|
||
|
})
|
||
|
);
|
||
|
});
|
||
|
|
||
|
var assertFindsIdentifierAssignmentExpressionRHS = (ast) => {
|
||
|
node = find('AssignmentExpression', ast);
|
||
|
assert.strictEqual(node.right.type, 'Identifier');
|
||
|
assert.strictEqual(node.right.name, 'async');
|
||
|
assert.deepEqual(node.right.loc, {
|
||
|
start: {
|
||
|
line: 1,
|
||
|
column: 6
|
||
|
},
|
||
|
end: {
|
||
|
line: 1,
|
||
|
column: 11
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
describe('linefeed after async (simple)', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'foo = async \t\t ',
|
||
|
', function() {',
|
||
|
'}'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('finds Identifier ExpressionStatement', () => {
|
||
|
assertFindsIdentifierAssignmentExpressionRHS(ast);
|
||
|
});
|
||
|
|
||
|
it('does not mark FunctionExpression as async', () => {
|
||
|
node = find('FunctionExpression', ast);
|
||
|
assert(!node.async, 'Expected node.async to be false');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (single line comment)', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'foo = async // flag enables async completion',
|
||
|
', function() {',
|
||
|
'}'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('finds Identifier ExpressionStatement', () => {
|
||
|
assertFindsIdentifierAssignmentExpressionRHS(ast);
|
||
|
});
|
||
|
|
||
|
it('does not mark FunctionExpression as async', () => {
|
||
|
node = find('FunctionExpression', ast);
|
||
|
assert(!node.async, 'Expected node.async to be false');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (multiline comment), function', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'foo = async /* flag enables async completion',
|
||
|
' of the callback */, function() {',
|
||
|
'}'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('finds Identifier ExpressionStatement', () => {
|
||
|
assertFindsIdentifierAssignmentExpressionRHS(ast);
|
||
|
});
|
||
|
|
||
|
it('does not mark FunctionExpression as async', () => {
|
||
|
node = find('FunctionExpression', ast);
|
||
|
assert(!node.async, 'Expected node.async to be false');
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe ('enhanced object literal', () => {
|
||
|
var node, code;
|
||
|
|
||
|
describe('-', () => {
|
||
|
beforeEach(() => {
|
||
|
code = [
|
||
|
'var x = {',
|
||
|
' async foo() {}',
|
||
|
'};'
|
||
|
];
|
||
|
node = find(
|
||
|
// TODO: Is it really supposed to mark the Property async? Why not the FunctionExpression?
|
||
|
'Property',
|
||
|
parse(code)
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('marks the node value as async', () =>
|
||
|
assert(node.value.async)
|
||
|
);
|
||
|
|
||
|
it('does not mark the node as async', () =>
|
||
|
assert(!node.async)
|
||
|
);
|
||
|
|
||
|
it('finds correct start position', () =>
|
||
|
assert.strictEqual(node.start, 12)
|
||
|
);
|
||
|
|
||
|
it('finds correct end position', () =>
|
||
|
assert.strictEqual(node.end, code[0].length + code[1].length + 1) // + 1 is due to newline char
|
||
|
);
|
||
|
|
||
|
it('finds correct start line/column', () =>
|
||
|
assert.deepEqual(node.loc.start, {
|
||
|
line: 2,
|
||
|
column: 2
|
||
|
})
|
||
|
);
|
||
|
|
||
|
it('finds correct end line/column', () =>
|
||
|
assert.deepEqual(node.loc.end, {
|
||
|
line: 2,
|
||
|
column: 16
|
||
|
})
|
||
|
);
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (simple)', () => {
|
||
|
it('fails to parse', () => {
|
||
|
assert.throws(() => parse([
|
||
|
'var x = {',
|
||
|
' async \t\t ',
|
||
|
' foo() {}',
|
||
|
'};'
|
||
|
]));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (single line comment)', () => {
|
||
|
it('fails to parse', () => {
|
||
|
assert.throws(() => parse([
|
||
|
'var x = {',
|
||
|
' async // flag enables async completion',
|
||
|
' foo() {}',
|
||
|
'};'
|
||
|
]));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (multiline comment) illegal decl', () => {
|
||
|
it('finds Identifier ExpressionStatement', () => {
|
||
|
assert.throws(() => parse([
|
||
|
'var x = {',
|
||
|
' async /* flag enables async completion',
|
||
|
' of the callback */ foo() {}',
|
||
|
'};'
|
||
|
]));
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe ('ArrowFunctionExpression', () => {
|
||
|
var node, code;
|
||
|
|
||
|
describe('-', () => {
|
||
|
beforeEach(() => {
|
||
|
code = 'var x = async () => {}';
|
||
|
node = find(
|
||
|
'ArrowFunctionExpression',
|
||
|
parse(code)
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('marks the node as async', () =>
|
||
|
assert(node.async)
|
||
|
);
|
||
|
|
||
|
it('finds correct start position', () =>
|
||
|
assert.strictEqual(node.start, 8)
|
||
|
);
|
||
|
|
||
|
it('finds correct end position', () =>
|
||
|
assert.strictEqual(node.end, code.length)
|
||
|
);
|
||
|
|
||
|
it('finds correct start line/column', () =>
|
||
|
assert.deepEqual(node.loc.start, {
|
||
|
line: 1,
|
||
|
column: 8
|
||
|
})
|
||
|
);
|
||
|
|
||
|
it('finds correct end line/column', () =>
|
||
|
assert.deepEqual(node.loc.end, {
|
||
|
line: 1,
|
||
|
column: code.length
|
||
|
})
|
||
|
);
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (simple)', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'var x = async \t\t ',
|
||
|
'()'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('fails to parse if linefeed preceeds arrow arguments', () => {
|
||
|
assert.throws(() => parse([
|
||
|
'var x = async \t\t ',
|
||
|
'() => {}'
|
||
|
]));
|
||
|
});
|
||
|
|
||
|
it('finds CallExpression with "async" Identifier callee', () => {
|
||
|
node = find('CallExpression', ast);
|
||
|
assert.strictEqual(node.callee.type, 'Identifier');
|
||
|
assert.strictEqual(node.callee.name, 'async');
|
||
|
assert.deepEqual(node.callee.loc, {
|
||
|
start: {
|
||
|
line: 1,
|
||
|
column: 8
|
||
|
},
|
||
|
end: {
|
||
|
line: 1,
|
||
|
column: 13
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (single line comment)', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'var x = async // flag enables async completion',
|
||
|
'()'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('fails to parse if linefeed preceeds arrow arguments', () => {
|
||
|
assert.throws(() => parse([
|
||
|
'var x = async \t\t ',
|
||
|
'() => {}'
|
||
|
]));
|
||
|
});
|
||
|
|
||
|
it('finds CallExpression with "async" Identifier callee', () => {
|
||
|
node = find('CallExpression', ast);
|
||
|
assert.strictEqual(node.callee.type, 'Identifier');
|
||
|
assert.strictEqual(node.callee.name, 'async');
|
||
|
assert.deepEqual(node.callee.loc, {
|
||
|
start: {
|
||
|
line: 1,
|
||
|
column: 8
|
||
|
},
|
||
|
end: {
|
||
|
line: 1,
|
||
|
column: 13
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('linefeed after async (multiline comment) arrow decl', () => {
|
||
|
var ast;
|
||
|
beforeEach(() => {
|
||
|
ast = parse([
|
||
|
'var x = async /* flag enables async completion',
|
||
|
' of the callback */()'
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
it('fails to parse if linefeed preceeds arrow arguments', () => {
|
||
|
assert.throws(() => parse([
|
||
|
'var x = async /* flag enables async completion',
|
||
|
' of the callback */() => {}'
|
||
|
]));
|
||
|
});
|
||
|
|
||
|
it('finds CallExpression with "async" Identifier callee', () => {
|
||
|
node = find('CallExpression', ast);
|
||
|
assert.strictEqual(node.callee.type, 'Identifier');
|
||
|
assert.strictEqual(node.callee.name, 'async');
|
||
|
assert.deepEqual(node.callee.loc, {
|
||
|
start: {
|
||
|
line: 1,
|
||
|
column: 8
|
||
|
},
|
||
|
end: {
|
||
|
line: 1,
|
||
|
column: 13
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('await', () => {
|
||
|
describe('-', () => {
|
||
|
var node;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
node = find(
|
||
|
'AwaitExpression',
|
||
|
parse([
|
||
|
'async function foo() {',
|
||
|
' x = await bar()',
|
||
|
'}'
|
||
|
])
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('finds correct start position', () =>
|
||
|
assert.strictEqual(node.start, 29)
|
||
|
);
|
||
|
|
||
|
it('finds correct end position', () =>
|
||
|
assert.strictEqual(node.end, 40)
|
||
|
);
|
||
|
|
||
|
it('finds correct start line/column', () =>
|
||
|
assert.deepEqual(node.loc.start, {
|
||
|
line: 2,
|
||
|
column: 6
|
||
|
})
|
||
|
);
|
||
|
|
||
|
it('finds correct end line/column', () =>
|
||
|
assert.deepEqual(node.loc.end, {
|
||
|
line: 2,
|
||
|
column: 17
|
||
|
})
|
||
|
);
|
||
|
});
|
||
|
|
||
|
describe('outside a function (awaitAnywhere)', () => {
|
||
|
var node;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
node = find(
|
||
|
'AwaitExpression',
|
||
|
parse(
|
||
|
'x = await bar()',
|
||
|
{awaitAnywhere:true}
|
||
|
)
|
||
|
);
|
||
|
});
|
||
|
|
||
|
it('finds correct start position', () =>
|
||
|
assert.strictEqual(node.start, 4)
|
||
|
);
|
||
|
|
||
|
it('finds correct start line/column', () =>
|
||
|
assert.deepEqual(node.loc.start, {
|
||
|
line: 1,
|
||
|
column: 4
|
||
|
})
|
||
|
);
|
||
|
|
||
|
it('finds correct end position', () =>
|
||
|
assert.strictEqual(node.end, 15)
|
||
|
);
|
||
|
|
||
|
it('finds correct end line/column', () =>
|
||
|
assert.deepEqual(node.loc.end, {
|
||
|
line: 1,
|
||
|
column: 15
|
||
|
})
|
||
|
);
|
||
|
});
|
||
|
});
|