NodeUtils.spec.ts 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. import * as ESTree from 'estree';
  2. import { assert } from 'chai';
  3. import { TStatement } from '../../../../src/types/node/TStatement';
  4. import { removeRangesFromStructure } from '../../../helpers/removeRangesFromStructure';
  5. import { NodeFactory } from '../../../../src/node/NodeFactory';
  6. import { NodeUtils } from '../../../../src/node/NodeUtils';
  7. describe('NodeUtils', () => {
  8. describe('addXVerbatimPropertyToLiterals (node: ESTree.Node): void', () => {
  9. let literalNode: ESTree.Literal,
  10. expectedLiteralNode: ESTree.Literal;
  11. before(() => {
  12. literalNode = NodeFactory.literalNode('value');
  13. delete literalNode['x-verbatim-property'];
  14. expectedLiteralNode = NodeFactory.literalNode('value');
  15. NodeUtils.addXVerbatimPropertyToLiterals(literalNode);
  16. });
  17. it('should add `x-verbatim-property` to `Literal` node', () => {
  18. assert.deepEqual(literalNode, expectedLiteralNode);
  19. });
  20. });
  21. describe('clone <T extends ESTree.Node> (astTree: T): T', () => {
  22. describe('Variant #1: simple AST-tree', () => {
  23. let programNode: ESTree.Program,
  24. expectedProgramNode: ESTree.Program;
  25. before(() => {
  26. // actual AST tree
  27. const expressionStatementNode1: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  28. const expressionStatementNode2: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  29. const ifStatementBlockStatementNode1: ESTree.BlockStatement = NodeFactory.blockStatementNode([
  30. expressionStatementNode1,
  31. expressionStatementNode2
  32. ]);
  33. const ifStatementNode1: ESTree.IfStatement = NodeFactory.ifStatementNode(
  34. NodeFactory.literalNode(true),
  35. ifStatementBlockStatementNode1
  36. );
  37. // expected AST tree
  38. const expressionStatementNode3: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  39. const expressionStatementNode4: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  40. const ifStatementBlockStatementNode2: ESTree.BlockStatement = NodeFactory.blockStatementNode([
  41. expressionStatementNode3,
  42. expressionStatementNode4
  43. ]);
  44. const ifStatementNode2: ESTree.IfStatement = NodeFactory.ifStatementNode(
  45. NodeFactory.literalNode(true),
  46. ifStatementBlockStatementNode2
  47. );
  48. programNode = NodeUtils.clone(
  49. NodeFactory.programNode([
  50. ifStatementNode1
  51. ])
  52. );
  53. expectedProgramNode = NodeUtils.parentize(
  54. NodeFactory.programNode([
  55. ifStatementNode2
  56. ])
  57. );
  58. });
  59. it('should clone given AST-tree', () => {
  60. assert.deepEqual(programNode, expectedProgramNode);
  61. });
  62. });
  63. describe('Variant #2: array expression with `null` element', () => {
  64. let programNode: ESTree.Program,
  65. expectedProgramNode: ESTree.Program;
  66. before(() => {
  67. // actual AST tree
  68. const arrayExpressionNode: ESTree.ArrayExpression = NodeFactory.arrayExpressionNode([
  69. NodeFactory.literalNode(1),
  70. NodeFactory.literalNode(2),
  71. <any>null,
  72. NodeFactory.literalNode(4)
  73. ]);
  74. const expressionStatementNode: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(
  75. arrayExpressionNode
  76. );
  77. // expected AST tree
  78. const expectedArrayExpressionNode: ESTree.ArrayExpression = NodeFactory.arrayExpressionNode([
  79. NodeFactory.literalNode(1),
  80. NodeFactory.literalNode(2),
  81. <any>null,
  82. NodeFactory.literalNode(4)
  83. ]);
  84. const expectedExpressionStatementNode: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(
  85. expectedArrayExpressionNode
  86. );
  87. programNode = NodeUtils.clone(
  88. NodeFactory.programNode([
  89. expressionStatementNode
  90. ])
  91. );
  92. expectedProgramNode = NodeUtils.parentize(
  93. NodeFactory.programNode([
  94. expectedExpressionStatementNode
  95. ])
  96. );
  97. });
  98. it('should clone given AST-tree', () => {
  99. assert.deepEqual(programNode, expectedProgramNode);
  100. });
  101. });
  102. });
  103. describe('convertCodeToStructure (code: string): ESTree.Statement[]', () => {
  104. let structure: TStatement[],
  105. expectedStructure: TStatement[];
  106. before(() => {
  107. const code: string = `
  108. var abc = 'cde';
  109. `;
  110. const identifierNode: ESTree.Identifier = NodeFactory.identifierNode('abc');
  111. const literalNode: ESTree.Literal = NodeFactory.literalNode('cde');
  112. const variableDeclaratorNode: ESTree.VariableDeclarator = NodeFactory
  113. .variableDeclaratorNode(identifierNode, literalNode);
  114. const variableDeclarationNode: ESTree.VariableDeclaration = NodeFactory
  115. .variableDeclarationNode([variableDeclaratorNode]);
  116. const programNode: ESTree.Program = NodeFactory.programNode([variableDeclarationNode]);
  117. programNode.parentNode = programNode;
  118. variableDeclarationNode.parentNode = programNode;
  119. variableDeclaratorNode.parentNode = variableDeclarationNode;
  120. identifierNode.parentNode = variableDeclaratorNode;
  121. literalNode.parentNode = variableDeclaratorNode;
  122. structure = removeRangesFromStructure(
  123. NodeUtils.convertCodeToStructure(code)
  124. );
  125. expectedStructure = [variableDeclarationNode];
  126. });
  127. it('should convert code to `ESTree.Node[]` structure array', () => {
  128. assert.deepEqual(structure, expectedStructure);
  129. });
  130. });
  131. describe('convertStructureToCode (structure: ESTree.Node[]): string', () => {
  132. let structure: ESTree.Node[],
  133. expectedCode: string;
  134. before(() => {
  135. structure = [
  136. NodeFactory.programNode([
  137. NodeFactory.variableDeclarationNode([
  138. NodeFactory.variableDeclaratorNode(
  139. NodeFactory.identifierNode('abc'),
  140. NodeFactory.literalNode('cde')
  141. )
  142. ])
  143. ])
  144. ];
  145. expectedCode = 'var abc = \'cde\';';
  146. });
  147. it('should convert `ESTree.Node[]` structure to source code', () => {
  148. assert.deepEqual(NodeUtils.convertStructureToCode(structure), expectedCode);
  149. });
  150. });
  151. describe('getBlockScopesOfNode (node: ESTree.Node, blockScopes: TNodeWithBlockScope[] = []): TNodeWithBlockScope[]', () => {
  152. let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
  153. ifStatementBlockStatementNode1: ESTree.BlockStatement,
  154. ifStatementBlockStatementNode2: ESTree.BlockStatement,
  155. ifStatementNode1: ESTree.IfStatement,
  156. ifStatementNode2: ESTree.IfStatement,
  157. expressionStatementNode3: ESTree.ExpressionStatement,
  158. expressionStatementNode2: ESTree.ExpressionStatement,
  159. expressionStatementNode1: ESTree.ExpressionStatement,
  160. functionDeclarationNode: ESTree.FunctionDeclaration,
  161. programNode: ESTree.Program;
  162. before(() => {
  163. expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  164. expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  165. expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  166. ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode([
  167. expressionStatementNode2,
  168. expressionStatementNode3
  169. ]);
  170. ifStatementNode2 = NodeFactory.ifStatementNode(
  171. NodeFactory.literalNode(true),
  172. ifStatementBlockStatementNode2
  173. );
  174. ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
  175. ifStatementNode2
  176. ]);
  177. ifStatementNode1 = NodeFactory.ifStatementNode(
  178. NodeFactory.literalNode(true),
  179. ifStatementBlockStatementNode1
  180. );
  181. functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
  182. expressionStatementNode1,
  183. ifStatementNode1
  184. ]);
  185. functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
  186. programNode = NodeFactory.programNode([
  187. functionDeclarationNode
  188. ]);
  189. programNode.parentNode = programNode;
  190. functionDeclarationNode.parentNode = programNode;
  191. functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
  192. expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
  193. ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
  194. ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
  195. ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
  196. ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
  197. expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
  198. });
  199. it('should return block-scope node for `program` node child', () => {
  200. assert.deepEqual(NodeUtils.getBlockScopesOfNode(programNode)[0], programNode);
  201. });
  202. it('should return block-scope node for `functionDeclaration` node child node #1', () => {
  203. assert.deepEqual(NodeUtils.getBlockScopesOfNode(functionDeclarationNode)[0], programNode);
  204. });
  205. it('should return block-scope node for `functionDeclaration blockStatement` node child node #1', () => {
  206. assert.deepEqual(NodeUtils.getBlockScopesOfNode(functionDeclarationBlockStatementNode)[0], programNode);
  207. });
  208. it('should return block-scope node for `expressionStatement` node #1 child node #1', () => {
  209. assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode1)[0], functionDeclarationBlockStatementNode);
  210. });
  211. it('should return block-scope node for `expressionStatement` node #1 child node #2', () => {
  212. assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode1)[1], programNode);
  213. });
  214. it('should return block-scope node for `ifStatement` node child node #1', () => {
  215. assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementNode1)[0], functionDeclarationBlockStatementNode);
  216. });
  217. it('should return block-scope node for `ifStatement` node child node #2', () => {
  218. assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementNode1)[1], programNode);
  219. });
  220. it('should return block-scope node for `ifStatement blockStatement` node #1 child node #1', () => {
  221. assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode1)[0], functionDeclarationBlockStatementNode);
  222. });
  223. it('should return block-scope node for `ifStatement blockStatement` node #1 child node #2', () => {
  224. assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode1)[1], programNode);
  225. });
  226. it('should return block-scope node for `ifStatement blockStatement` node #2 child node #1', () => {
  227. assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode2)[0], functionDeclarationBlockStatementNode);
  228. });
  229. it('should return block-scope node for `ifStatement blockStatement` node #1 child node #2', () => {
  230. assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode2)[1], programNode);
  231. });
  232. it('should return block-scope node for `expressionStatement` node #3 child node #1', () => {
  233. assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode3)[0], functionDeclarationBlockStatementNode);
  234. });
  235. it('should return block-scope node for `expressionStatement` node #3 child node #2', () => {
  236. assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode3)[1], programNode);
  237. });
  238. it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
  239. assert.throws(() => NodeUtils.getBlockScopesOfNode(expressionStatementNode2)[0], ReferenceError);
  240. });
  241. });
  242. describe('getNextSiblingStatementNode (node: ESTree.Statement): TStatement | null', () => {
  243. describe('Variant #1: block statement node as scope node', () => {
  244. let statementNode1: ESTree.Statement,
  245. statementNode2: ESTree.Statement,
  246. statementNode3: ESTree.Statement;
  247. before(() => {
  248. statementNode1 = NodeFactory.expressionStatementNode(
  249. NodeFactory.identifierNode('a')
  250. );
  251. statementNode2 = NodeFactory.expressionStatementNode(
  252. NodeFactory.identifierNode('b')
  253. );
  254. statementNode3 = NodeFactory.expressionStatementNode(
  255. NodeFactory.identifierNode('c')
  256. );
  257. const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
  258. statementNode1,
  259. statementNode2,
  260. statementNode3
  261. ]);
  262. statementNode1.parentNode = blockStatementNode;
  263. statementNode2.parentNode = blockStatementNode;
  264. statementNode3.parentNode = blockStatementNode;
  265. });
  266. it('should return next sibling statement node', () => {
  267. assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode1), statementNode2);
  268. });
  269. it('should return next sibling statement node', () => {
  270. assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode2), statementNode3);
  271. });
  272. it('should return `null` if given statement node is last node in the scope', () => {
  273. assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode3), null);
  274. });
  275. });
  276. describe('Variant #2: switch case node as scope node', () => {
  277. let statementNode1: ESTree.Statement,
  278. statementNode2: ESTree.Statement,
  279. statementNode3: ESTree.Statement;
  280. before(() => {
  281. statementNode1 = NodeFactory.expressionStatementNode(
  282. NodeFactory.identifierNode('a')
  283. );
  284. statementNode2 = NodeFactory.expressionStatementNode(
  285. NodeFactory.identifierNode('b')
  286. );
  287. statementNode3 = NodeFactory.expressionStatementNode(
  288. NodeFactory.identifierNode('c')
  289. );
  290. const switchCaseNode: ESTree.SwitchCase = NodeFactory.switchCaseNode(
  291. NodeFactory.literalNode(true),
  292. [
  293. statementNode1,
  294. statementNode2,
  295. statementNode3
  296. ]
  297. );
  298. statementNode1.parentNode = switchCaseNode;
  299. statementNode2.parentNode = switchCaseNode;
  300. statementNode3.parentNode = switchCaseNode;
  301. });
  302. it('should return next sibling statement node', () => {
  303. assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode1), statementNode2);
  304. });
  305. it('should return next sibling statement node', () => {
  306. assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode2), statementNode3);
  307. });
  308. it('should return `null` if given statement node is last node in the scope', () => {
  309. assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode3), null);
  310. });
  311. });
  312. });
  313. describe('getPreviousSiblingStatementNode (node: ESTree.Statement): TStatement | null', () => {
  314. describe('Variant #1: block statement node as scope node', () => {
  315. let statementNode1: ESTree.Statement,
  316. statementNode2: ESTree.Statement,
  317. statementNode3: ESTree.Statement;
  318. before(() => {
  319. statementNode1 = NodeFactory.expressionStatementNode(
  320. NodeFactory.identifierNode('a')
  321. );
  322. statementNode2 = NodeFactory.expressionStatementNode(
  323. NodeFactory.identifierNode('b')
  324. );
  325. statementNode3 = NodeFactory.expressionStatementNode(
  326. NodeFactory.identifierNode('c')
  327. );
  328. const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
  329. statementNode1,
  330. statementNode2,
  331. statementNode3
  332. ]);
  333. statementNode1.parentNode = blockStatementNode;
  334. statementNode2.parentNode = blockStatementNode;
  335. statementNode3.parentNode = blockStatementNode;
  336. });
  337. it('should return next sibling statement node', () => {
  338. assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode1), null);
  339. });
  340. it('should return next sibling statement node', () => {
  341. assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode2), statementNode1);
  342. });
  343. it('should return `null` if given statement node is last node in the scope', () => {
  344. assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode3), statementNode2);
  345. });
  346. });
  347. describe('Variant #2: switch case node as scope node', () => {
  348. let statementNode1: ESTree.Statement,
  349. statementNode2: ESTree.Statement,
  350. statementNode3: ESTree.Statement;
  351. before(() => {
  352. statementNode1 = NodeFactory.expressionStatementNode(
  353. NodeFactory.identifierNode('a')
  354. );
  355. statementNode2 = NodeFactory.expressionStatementNode(
  356. NodeFactory.identifierNode('b')
  357. );
  358. statementNode3 = NodeFactory.expressionStatementNode(
  359. NodeFactory.identifierNode('c')
  360. );
  361. const switchCaseNode: ESTree.SwitchCase = NodeFactory.switchCaseNode(
  362. NodeFactory.literalNode(true),
  363. [
  364. statementNode1,
  365. statementNode2,
  366. statementNode3
  367. ]
  368. );
  369. statementNode1.parentNode = switchCaseNode;
  370. statementNode2.parentNode = switchCaseNode;
  371. statementNode3.parentNode = switchCaseNode;
  372. });
  373. it('should return next sibling statement node', () => {
  374. assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode1), null);
  375. });
  376. it('should return next sibling statement node', () => {
  377. assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode2), statementNode1);
  378. });
  379. it('should return `null` if given statement node is last node in the scope', () => {
  380. assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode3), statementNode2);
  381. });
  382. });
  383. });
  384. describe('getScopeOfNode (node: ESTree.Node): TNodeWithScope | null', () => {
  385. let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
  386. ifStatementBlockStatementNode1: ESTree.BlockStatement,
  387. ifStatementBlockStatementNode2: ESTree.BlockStatement,
  388. ifStatementBlockStatementNode3: ESTree.BlockStatement,
  389. ifStatementNode1: ESTree.IfStatement,
  390. ifStatementNode2: ESTree.IfStatement,
  391. ifStatementNode3: ESTree.IfStatement,
  392. switchCaseNode: ESTree.SwitchCase,
  393. switchStatementNode: ESTree.SwitchStatement,
  394. expressionStatementNode3: ESTree.ExpressionStatement,
  395. expressionStatementNode2: ESTree.ExpressionStatement,
  396. expressionStatementNode1: ESTree.ExpressionStatement,
  397. functionDeclarationNode: ESTree.FunctionDeclaration,
  398. programNode: ESTree.Program;
  399. before(() => {
  400. expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  401. expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  402. expressionStatementNode3 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  403. ifStatementBlockStatementNode3 = NodeFactory.blockStatementNode([
  404. expressionStatementNode2,
  405. expressionStatementNode3
  406. ]);
  407. ifStatementNode3 = NodeFactory.ifStatementNode(
  408. NodeFactory.literalNode(true),
  409. ifStatementBlockStatementNode3
  410. );
  411. ifStatementBlockStatementNode2 = NodeFactory.blockStatementNode();
  412. ifStatementBlockStatementNode1 = NodeFactory.blockStatementNode([
  413. ifStatementNode3
  414. ]);
  415. ifStatementNode2 = NodeFactory.ifStatementNode(
  416. NodeFactory.literalNode(true),
  417. ifStatementBlockStatementNode2
  418. );
  419. ifStatementNode1 = NodeFactory.ifStatementNode(
  420. NodeFactory.literalNode(true),
  421. ifStatementBlockStatementNode1
  422. );
  423. switchCaseNode = NodeFactory.switchCaseNode(
  424. NodeFactory.literalNode(1),
  425. [
  426. ifStatementNode2
  427. ]
  428. );
  429. switchStatementNode = NodeFactory.switchStatementNode(
  430. NodeFactory.literalNode(1),
  431. [
  432. switchCaseNode
  433. ]
  434. );
  435. functionDeclarationBlockStatementNode = NodeFactory.blockStatementNode([
  436. expressionStatementNode1,
  437. ifStatementNode1,
  438. switchStatementNode
  439. ]);
  440. functionDeclarationNode = NodeFactory.functionDeclarationNode('test', [], functionDeclarationBlockStatementNode);
  441. programNode = NodeFactory.programNode([
  442. functionDeclarationNode
  443. ]);
  444. programNode.parentNode = programNode;
  445. functionDeclarationNode.parentNode = programNode;
  446. functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
  447. expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
  448. ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
  449. ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
  450. switchStatementNode.parentNode = functionDeclarationBlockStatementNode;
  451. switchCaseNode.parentNode = switchStatementNode;
  452. ifStatementNode2.parentNode = switchCaseNode;
  453. ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
  454. ifStatementNode3.parentNode = ifStatementBlockStatementNode1;
  455. ifStatementBlockStatementNode3.parentNode = ifStatementNode3;
  456. expressionStatementNode3.parentNode = ifStatementBlockStatementNode3;
  457. });
  458. it('should return scope node for `program` node child', () => {
  459. assert.deepEqual(NodeUtils.getScopeOfNode(programNode), programNode);
  460. });
  461. it('should return scope node for `functionDeclaration` node child node #1', () => {
  462. assert.deepEqual(NodeUtils.getScopeOfNode(functionDeclarationNode), programNode);
  463. });
  464. it('should return scope node for `functionDeclaration blockStatement` node child node #1', () => {
  465. assert.deepEqual(NodeUtils.getScopeOfNode(functionDeclarationBlockStatementNode), programNode);
  466. });
  467. it('should return scope node for `expressionStatement` node #1 child node', () => {
  468. assert.deepEqual(NodeUtils.getScopeOfNode(expressionStatementNode1), functionDeclarationBlockStatementNode);
  469. });
  470. it('should return scope node for `ifStatement` node #1 child node', () => {
  471. assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementNode1), functionDeclarationBlockStatementNode);
  472. });
  473. it('should return scope node for `switchStatement` node child node', () => {
  474. assert.deepEqual(NodeUtils.getScopeOfNode(switchStatementNode), functionDeclarationBlockStatementNode);
  475. });
  476. it('should return scope node for `switchCase` node child node', () => {
  477. assert.deepEqual(NodeUtils.getScopeOfNode(switchCaseNode), functionDeclarationBlockStatementNode);
  478. });
  479. it('should return scope node for `ifStatement` node #2 child node', () => {
  480. assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementNode2), switchCaseNode);
  481. });
  482. it('should return scope node for `ifStatement blockStatement` node #2 child node', () => {
  483. assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementBlockStatementNode2), switchCaseNode);
  484. });
  485. it('should return scope node for `ifStatement blockStatement` node #1 child node', () => {
  486. assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementBlockStatementNode1), functionDeclarationBlockStatementNode);
  487. });
  488. it('should return scope node for `ifStatement blockStatement` node #3 child node', () => {
  489. assert.deepEqual(NodeUtils.getScopeOfNode(ifStatementBlockStatementNode3), ifStatementBlockStatementNode1);
  490. });
  491. it('should return scope node for `expressionStatement` node #3 child node', () => {
  492. assert.deepEqual(NodeUtils.getScopeOfNode(expressionStatementNode3), ifStatementBlockStatementNode3);
  493. });
  494. it('should throw a `ReferenceError` if node has no `parentNode` property', () => {
  495. assert.throws(() => NodeUtils.getScopeOfNode(expressionStatementNode2), ReferenceError);
  496. });
  497. });
  498. describe('getUnaryExpressionArgumentNode (unaryExpressionNode: ESTree.UnaryExpression): ESTree.Node', () => {
  499. let expectedNode: ESTree.Literal,
  500. unaryExpressionArgumentNode: ESTree.Node;
  501. before(() => {
  502. const literalNode: ESTree.Literal = NodeFactory.literalNode('test');
  503. const unaryExpressionNode2: ESTree.UnaryExpression = NodeFactory.unaryExpressionNode('!', literalNode);
  504. const unaryExpressionNode1: ESTree.UnaryExpression = NodeFactory.unaryExpressionNode('!', unaryExpressionNode2);
  505. const expressionStatementNode: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(unaryExpressionNode1);
  506. const programNode: ESTree.Program = NodeFactory.programNode([
  507. expressionStatementNode
  508. ]);
  509. programNode.parentNode = programNode;
  510. expressionStatementNode.parentNode = programNode;
  511. unaryExpressionNode1.parentNode = expressionStatementNode;
  512. unaryExpressionNode2.parentNode = unaryExpressionNode1;
  513. literalNode.parentNode = unaryExpressionNode2;
  514. unaryExpressionArgumentNode = NodeUtils.getUnaryExpressionArgumentNode(unaryExpressionNode1);
  515. expectedNode = literalNode;
  516. });
  517. it('should return unary expression argument node', () => {
  518. assert.deepEqual(unaryExpressionArgumentNode, expectedNode);
  519. });
  520. });
  521. describe('parentize <T extends ESTree.Node> (astTree: T): T', () => {
  522. let ifStatementNode: ESTree.IfStatement,
  523. ifStatementBlockStatementNode: ESTree.BlockStatement,
  524. expressionStatementNode1: ESTree.ExpressionStatement,
  525. expressionStatementNode2: ESTree.ExpressionStatement,
  526. programNode: ESTree.Program;
  527. beforeEach(() => {
  528. expressionStatementNode1 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  529. expressionStatementNode2 = NodeFactory.expressionStatementNode(NodeFactory.identifierNode('identifier'));
  530. ifStatementBlockStatementNode = NodeFactory.blockStatementNode([
  531. expressionStatementNode1,
  532. expressionStatementNode2
  533. ]);
  534. ifStatementNode = NodeFactory.ifStatementNode(
  535. NodeFactory.literalNode(true),
  536. ifStatementBlockStatementNode
  537. );
  538. });
  539. describe('Variant #1: parentize AST-tree with `ProgramNode` as root node', () => {
  540. beforeEach(() => {
  541. programNode = NodeFactory.programNode([
  542. ifStatementNode
  543. ]);
  544. programNode = NodeUtils.parentize(programNode);
  545. });
  546. it('should parentize `program` node with `ProgramNode` as root node', () => {
  547. assert.deepEqual(programNode.parentNode, programNode);
  548. });
  549. it('should parentize `ifStatement` node with `ProgramNode` as root node', () => {
  550. assert.deepEqual(ifStatementNode.parentNode, programNode);
  551. });
  552. it('should parentize `ifStatement blockStatement` node with `ProgramNode` as root node', () => {
  553. assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode);
  554. });
  555. it('should parentize `expressionStatement` node #1 with `ProgramNode` as root node', () => {
  556. assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode);
  557. });
  558. it('should parentize `expressionStatement` node #2 with `ProgramNode` as root node', () => {
  559. assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode);
  560. });
  561. });
  562. describe('Variant #2: parentize AST-tree', () => {
  563. beforeEach(() => {
  564. ifStatementNode = NodeUtils.parentize(ifStatementNode);
  565. });
  566. it('should parentize `ifStatement` node', () => {
  567. assert.deepEqual(ifStatementNode.parentNode, ifStatementNode);
  568. });
  569. it('should parentize `ifStatement blockStatement` node', () => {
  570. assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode);
  571. });
  572. it('should parentize `expressionStatement` node #1', () => {
  573. assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode);
  574. });
  575. it('should parentize `expressionStatement` node #2', () => {
  576. assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode);
  577. });
  578. });
  579. });
  580. describe('parentizeNode <T extends ESTree.Node = ESTree.Program> (node: T, parentNode: ESTree.Node): T', () => {
  581. describe('Variant #1: node with parent node', () => {
  582. const identifier: ESTree.Identifier = NodeFactory.identifierNode('foo');
  583. const breakStatement: ESTree.BreakStatement = NodeFactory.breakStatement(identifier);
  584. const expectedResult: ESTree.Identifier = NodeUtils.clone(identifier);
  585. let result: ESTree.Identifier;
  586. before(() => {
  587. expectedResult.parentNode = breakStatement;
  588. result = NodeUtils.parentizeNode(identifier, breakStatement);
  589. });
  590. it('should parentize given node', () => {
  591. assert.deepEqual(result, expectedResult);
  592. });
  593. });
  594. describe('Variant #2: node without parent node', () => {
  595. const identifier: ESTree.Identifier = NodeFactory.identifierNode('Foo');
  596. const expectedResult: ESTree.Identifier = NodeUtils.clone(identifier);
  597. let result: ESTree.Identifier;
  598. before(() => {
  599. expectedResult.parentNode = expectedResult;
  600. result = NodeUtils.parentizeNode(identifier, <any>null);
  601. });
  602. it('should parentize given node', () => {
  603. assert.deepEqual(result, expectedResult);
  604. });
  605. });
  606. });
  607. });