test.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. 'use strict';
  2. var acorn = require('acorn');
  3. require('../')(acorn);
  4. var estraverse = require('estraverse');
  5. var xtend = require('xtend');
  6. var assert = require('assert');
  7. function find (type, ast, skip) {
  8. skip = skip || 0;
  9. var skipped = 0;
  10. var found;
  11. estraverse.traverse(ast, {
  12. enter: (node) => {
  13. if (found) {
  14. return estraverse.VisitorOption.Skip;
  15. }
  16. if (node.type == type) {
  17. if (skipped === skip) {
  18. found = node;
  19. return estraverse.VisitorOption.Skip;
  20. }
  21. skipped++;
  22. }
  23. }
  24. });
  25. if (!found) {
  26. throw new Error('did not find AwaitExpression (skipped ' + skipped + '/' + skip + ')');
  27. }
  28. return found;
  29. }
  30. function extendOptions(pluginOptions, acornOptions) {
  31. return xtend({
  32. sourceType: 'module',
  33. ecmaVersion: 8,
  34. locations: true,
  35. ranges: true,
  36. plugins: {asyncawait: pluginOptions || pluginOptions !== false}
  37. }, acornOptions);
  38. }
  39. function parse(code, pluginOptions, acornOptions) {
  40. if (Array.isArray(code)) {
  41. code = code.join('\n');
  42. }
  43. var options = extendOptions(pluginOptions, acornOptions);
  44. return acorn.parse(code, options);
  45. }
  46. describe('async', () => {
  47. describe ('function declaration', () => {
  48. var node;
  49. describe('-', () => {
  50. beforeEach(() => {
  51. node = find(
  52. 'FunctionDeclaration',
  53. parse([
  54. 'async function foo() {',
  55. ' x = await bar()',
  56. '}'
  57. ])
  58. );
  59. });
  60. it('marks the node as async', () =>
  61. assert(node.async)
  62. );
  63. it('finds correct start position', () =>
  64. assert.strictEqual(node.start, 0)
  65. );
  66. it('finds correct end position', () =>
  67. assert.strictEqual(node.end, 42)
  68. );
  69. it('finds correct start line/column', () =>
  70. assert.deepEqual(node.loc.start, {
  71. line: 1,
  72. column: 0
  73. })
  74. );
  75. it('finds correct end line/column', () =>
  76. assert.deepEqual(node.loc.end, {
  77. line: 3,
  78. column: 1
  79. })
  80. );
  81. });
  82. var assertFindsIdentifierExpressionStatement = (ast) => {
  83. node = find('ExpressionStatement', ast);
  84. assert.strictEqual(node.expression.type, 'Identifier');
  85. assert.strictEqual(node.expression.name, 'async');
  86. assert.deepEqual(node.expression.loc, {
  87. start: {
  88. line: 1,
  89. column: 0
  90. },
  91. end: {
  92. line: 1,
  93. column: 5
  94. }
  95. });
  96. };
  97. describe('linefeed after async (simple)', () => {
  98. var ast;
  99. beforeEach(() => {
  100. ast = parse([
  101. 'async \t\t ',
  102. 'function foo() {',
  103. '}'
  104. ]);
  105. });
  106. it('finds Identifier ExpressionStatement', () => {
  107. assertFindsIdentifierExpressionStatement(ast);
  108. });
  109. it('does not mark FunctionDeclaration as async', () => {
  110. node = find('FunctionDeclaration', ast);
  111. assert(!node.async, 'Expected node.async to be false');
  112. });
  113. });
  114. describe('linefeed after async (single line comment)', () => {
  115. var ast;
  116. beforeEach(() => {
  117. ast = parse([
  118. 'async // flag enables async completion',
  119. 'function foo() {',
  120. '}'
  121. ]);
  122. });
  123. it('finds Identifier ExpressionStatement', () => {
  124. assertFindsIdentifierExpressionStatement(ast);
  125. });
  126. it('does not mark FunctionDeclaration as async', () => {
  127. node = find('FunctionDeclaration', ast);
  128. assert(!node.async, 'Expected node.async to be false');
  129. });
  130. });
  131. describe('linefeed after async (multiline comment) function', () => {
  132. var ast;
  133. beforeEach(() => {
  134. ast = parse([
  135. 'async /* flag enables async completion',
  136. ' of the callback */function foo() {',
  137. '}'
  138. ]);
  139. });
  140. it('finds Identifier ExpressionStatement', () => {
  141. assertFindsIdentifierExpressionStatement(ast);
  142. });
  143. it('does not mark FunctionDeclaration as async', () => {
  144. node = find('FunctionDeclaration', ast);
  145. assert(!node.async, 'Expected node.async to be false');
  146. });
  147. });
  148. });
  149. describe ('function expression', () => {
  150. var node, code;
  151. describe('-', () => {
  152. beforeEach(() => {
  153. code = [
  154. 'foo = async function () {',
  155. ' x = await bar()',
  156. '}'
  157. ];
  158. node = find(
  159. 'FunctionExpression',
  160. parse(code)
  161. );
  162. });
  163. it('marks the node as async', () =>
  164. assert(node.async)
  165. );
  166. it('finds correct start position', () =>
  167. assert.strictEqual(node.start, 6)
  168. );
  169. it('finds correct end position', () =>
  170. assert.strictEqual(node.end, code.join('\n').length)
  171. );
  172. it('finds correct start line/column', () =>
  173. assert.deepEqual(node.loc.start, {
  174. line: 1,
  175. column: 6
  176. })
  177. );
  178. it('finds correct end line/column', () =>
  179. assert.deepEqual(node.loc.end, {
  180. line: 3,
  181. column: 1
  182. })
  183. );
  184. });
  185. var assertFindsIdentifierAssignmentExpressionRHS = (ast) => {
  186. node = find('AssignmentExpression', ast);
  187. assert.strictEqual(node.right.type, 'Identifier');
  188. assert.strictEqual(node.right.name, 'async');
  189. assert.deepEqual(node.right.loc, {
  190. start: {
  191. line: 1,
  192. column: 6
  193. },
  194. end: {
  195. line: 1,
  196. column: 11
  197. }
  198. });
  199. };
  200. describe('linefeed after async (simple)', () => {
  201. var ast;
  202. beforeEach(() => {
  203. ast = parse([
  204. 'foo = async \t\t ',
  205. ', function() {',
  206. '}'
  207. ]);
  208. });
  209. it('finds Identifier ExpressionStatement', () => {
  210. assertFindsIdentifierAssignmentExpressionRHS(ast);
  211. });
  212. it('does not mark FunctionExpression as async', () => {
  213. node = find('FunctionExpression', ast);
  214. assert(!node.async, 'Expected node.async to be false');
  215. });
  216. });
  217. describe('linefeed after async (single line comment)', () => {
  218. var ast;
  219. beforeEach(() => {
  220. ast = parse([
  221. 'foo = async // flag enables async completion',
  222. ', function() {',
  223. '}'
  224. ]);
  225. });
  226. it('finds Identifier ExpressionStatement', () => {
  227. assertFindsIdentifierAssignmentExpressionRHS(ast);
  228. });
  229. it('does not mark FunctionExpression as async', () => {
  230. node = find('FunctionExpression', ast);
  231. assert(!node.async, 'Expected node.async to be false');
  232. });
  233. });
  234. describe('linefeed after async (multiline comment), function', () => {
  235. var ast;
  236. beforeEach(() => {
  237. ast = parse([
  238. 'foo = async /* flag enables async completion',
  239. ' of the callback */, function() {',
  240. '}'
  241. ]);
  242. });
  243. it('finds Identifier ExpressionStatement', () => {
  244. assertFindsIdentifierAssignmentExpressionRHS(ast);
  245. });
  246. it('does not mark FunctionExpression as async', () => {
  247. node = find('FunctionExpression', ast);
  248. assert(!node.async, 'Expected node.async to be false');
  249. });
  250. });
  251. });
  252. describe ('enhanced object literal', () => {
  253. var node, code;
  254. describe('-', () => {
  255. beforeEach(() => {
  256. code = [
  257. 'var x = {',
  258. ' async foo() {}',
  259. '};'
  260. ];
  261. node = find(
  262. // TODO: Is it really supposed to mark the Property async? Why not the FunctionExpression?
  263. 'Property',
  264. parse(code)
  265. );
  266. });
  267. it('marks the node value as async', () =>
  268. assert(node.value.async)
  269. );
  270. it('does not mark the node as async', () =>
  271. assert(!node.async)
  272. );
  273. it('finds correct start position', () =>
  274. assert.strictEqual(node.start, 12)
  275. );
  276. it('finds correct end position', () =>
  277. assert.strictEqual(node.end, code[0].length + code[1].length + 1) // + 1 is due to newline char
  278. );
  279. it('finds correct start line/column', () =>
  280. assert.deepEqual(node.loc.start, {
  281. line: 2,
  282. column: 2
  283. })
  284. );
  285. it('finds correct end line/column', () =>
  286. assert.deepEqual(node.loc.end, {
  287. line: 2,
  288. column: 16
  289. })
  290. );
  291. });
  292. describe('linefeed after async (simple)', () => {
  293. it('fails to parse', () => {
  294. assert.throws(() => parse([
  295. 'var x = {',
  296. ' async \t\t ',
  297. ' foo() {}',
  298. '};'
  299. ]));
  300. });
  301. });
  302. describe('linefeed after async (single line comment)', () => {
  303. it('fails to parse', () => {
  304. assert.throws(() => parse([
  305. 'var x = {',
  306. ' async // flag enables async completion',
  307. ' foo() {}',
  308. '};'
  309. ]));
  310. });
  311. });
  312. describe('linefeed after async (multiline comment) illegal decl', () => {
  313. it('finds Identifier ExpressionStatement', () => {
  314. assert.throws(() => parse([
  315. 'var x = {',
  316. ' async /* flag enables async completion',
  317. ' of the callback */ foo() {}',
  318. '};'
  319. ]));
  320. });
  321. });
  322. });
  323. describe ('ArrowFunctionExpression', () => {
  324. var node, code;
  325. describe('-', () => {
  326. beforeEach(() => {
  327. code = 'var x = async () => {}';
  328. node = find(
  329. 'ArrowFunctionExpression',
  330. parse(code)
  331. );
  332. });
  333. it('marks the node as async', () =>
  334. assert(node.async)
  335. );
  336. it('finds correct start position', () =>
  337. assert.strictEqual(node.start, 8)
  338. );
  339. it('finds correct end position', () =>
  340. assert.strictEqual(node.end, code.length)
  341. );
  342. it('finds correct start line/column', () =>
  343. assert.deepEqual(node.loc.start, {
  344. line: 1,
  345. column: 8
  346. })
  347. );
  348. it('finds correct end line/column', () =>
  349. assert.deepEqual(node.loc.end, {
  350. line: 1,
  351. column: code.length
  352. })
  353. );
  354. });
  355. describe('linefeed after async (simple)', () => {
  356. var ast;
  357. beforeEach(() => {
  358. ast = parse([
  359. 'var x = async \t\t ',
  360. '()'
  361. ]);
  362. });
  363. it('fails to parse if linefeed preceeds arrow arguments', () => {
  364. assert.throws(() => parse([
  365. 'var x = async \t\t ',
  366. '() => {}'
  367. ]));
  368. });
  369. it('finds CallExpression with "async" Identifier callee', () => {
  370. node = find('CallExpression', ast);
  371. assert.strictEqual(node.callee.type, 'Identifier');
  372. assert.strictEqual(node.callee.name, 'async');
  373. assert.deepEqual(node.callee.loc, {
  374. start: {
  375. line: 1,
  376. column: 8
  377. },
  378. end: {
  379. line: 1,
  380. column: 13
  381. }
  382. });
  383. });
  384. });
  385. describe('linefeed after async (single line comment)', () => {
  386. var ast;
  387. beforeEach(() => {
  388. ast = parse([
  389. 'var x = async // flag enables async completion',
  390. '()'
  391. ]);
  392. });
  393. it('fails to parse if linefeed preceeds arrow arguments', () => {
  394. assert.throws(() => parse([
  395. 'var x = async \t\t ',
  396. '() => {}'
  397. ]));
  398. });
  399. it('finds CallExpression with "async" Identifier callee', () => {
  400. node = find('CallExpression', ast);
  401. assert.strictEqual(node.callee.type, 'Identifier');
  402. assert.strictEqual(node.callee.name, 'async');
  403. assert.deepEqual(node.callee.loc, {
  404. start: {
  405. line: 1,
  406. column: 8
  407. },
  408. end: {
  409. line: 1,
  410. column: 13
  411. }
  412. });
  413. });
  414. });
  415. describe('linefeed after async (multiline comment) arrow decl', () => {
  416. var ast;
  417. beforeEach(() => {
  418. ast = parse([
  419. 'var x = async /* flag enables async completion',
  420. ' of the callback */()'
  421. ]);
  422. });
  423. it('fails to parse if linefeed preceeds arrow arguments', () => {
  424. assert.throws(() => parse([
  425. 'var x = async /* flag enables async completion',
  426. ' of the callback */() => {}'
  427. ]));
  428. });
  429. it('finds CallExpression with "async" Identifier callee', () => {
  430. node = find('CallExpression', ast);
  431. assert.strictEqual(node.callee.type, 'Identifier');
  432. assert.strictEqual(node.callee.name, 'async');
  433. assert.deepEqual(node.callee.loc, {
  434. start: {
  435. line: 1,
  436. column: 8
  437. },
  438. end: {
  439. line: 1,
  440. column: 13
  441. }
  442. });
  443. });
  444. });
  445. });
  446. });
  447. describe('await', () => {
  448. describe('-', () => {
  449. var node;
  450. beforeEach(() => {
  451. node = find(
  452. 'AwaitExpression',
  453. parse([
  454. 'async function foo() {',
  455. ' x = await bar()',
  456. '}'
  457. ])
  458. );
  459. });
  460. it('finds correct start position', () =>
  461. assert.strictEqual(node.start, 29)
  462. );
  463. it('finds correct end position', () =>
  464. assert.strictEqual(node.end, 40)
  465. );
  466. it('finds correct start line/column', () =>
  467. assert.deepEqual(node.loc.start, {
  468. line: 2,
  469. column: 6
  470. })
  471. );
  472. it('finds correct end line/column', () =>
  473. assert.deepEqual(node.loc.end, {
  474. line: 2,
  475. column: 17
  476. })
  477. );
  478. });
  479. describe('outside a function (awaitAnywhere)', () => {
  480. var node;
  481. beforeEach(() => {
  482. node = find(
  483. 'AwaitExpression',
  484. parse(
  485. 'x = await bar()',
  486. {awaitAnywhere:true}
  487. )
  488. );
  489. });
  490. it('finds correct start position', () =>
  491. assert.strictEqual(node.start, 4)
  492. );
  493. it('finds correct start line/column', () =>
  494. assert.deepEqual(node.loc.start, {
  495. line: 1,
  496. column: 4
  497. })
  498. );
  499. it('finds correct end position', () =>
  500. assert.strictEqual(node.end, 15)
  501. );
  502. it('finds correct end line/column', () =>
  503. assert.deepEqual(node.loc.end, {
  504. line: 1,
  505. column: 15
  506. })
  507. );
  508. });
  509. });