NodeUtils.spec.ts 32 KB

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