NodeUtils.spec.ts 33 KB

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