NodeUtils.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import * as estraverse from 'estraverse';
  2. import { IBlockStatementNode } from "./interfaces/nodes/IBlockStatementNode";
  3. import { IIdentifierNode } from "./interfaces/nodes/IIdentifierNode";
  4. import { ILiteralNode } from "./interfaces/nodes/ILiteralNode";
  5. import { IMemberExpressionNode } from "./interfaces/nodes/IMemberExpressionNode";
  6. import { IProgramNode } from "./interfaces/nodes/IProgramNode";
  7. import { IPropertyNode } from "./interfaces/nodes/IPropertyNode";
  8. import { INode } from './interfaces/nodes/INode';
  9. import { IVariableDeclaratorNode } from "./interfaces/nodes/IVariableDeclaratorNode";
  10. import { TBlockScopeNode } from "./types/TBlockScopeNode";
  11. import { NodeType } from "./enums/NodeType";
  12. import { Utils } from "./Utils";
  13. export class NodeUtils {
  14. /**
  15. * @type {string[]}
  16. */
  17. private static scopeNodes: string[] = [
  18. NodeType.ArrowFunctionExpression,
  19. NodeType.FunctionDeclaration,
  20. NodeType.FunctionExpression,
  21. NodeType.MethodDefinition
  22. ];
  23. /**
  24. * @param node
  25. */
  26. public static addXVerbatimPropertyToLiterals (node: INode): void {
  27. estraverse.replace(node, {
  28. enter: (node: INode, parentNode: INode): any => {
  29. if (NodeUtils.isLiteralNode(node)) {
  30. node['x-verbatim-property'] = node.raw;
  31. }
  32. }
  33. });
  34. }
  35. /**
  36. * @param blockScopeBody
  37. * @param node
  38. */
  39. public static appendNode (blockScopeBody: INode[], node: INode): void {
  40. if (!NodeUtils.validateNode(node)) {
  41. return;
  42. }
  43. blockScopeBody.push(node);
  44. }
  45. /**
  46. * @param node
  47. * @param index
  48. * @returns {INode}
  49. */
  50. public static getBlockScopeNodeByIndex (node: INode, index: number = 0): INode {
  51. if (NodeUtils.isNodeHasBlockScope(node) && node.body[index]) {
  52. return node.body[index];
  53. }
  54. return node;
  55. }
  56. /**
  57. * @param node
  58. * @param depth
  59. * @returns {INode}
  60. */
  61. public static getBlockScopeOfNode (node: INode, depth: number = 0): TBlockScopeNode {
  62. if (!node.parentNode) {
  63. throw new ReferenceError('`parentNode` property of given node is `undefined`');
  64. }
  65. if (node.parentNode.type === NodeType.Program) {
  66. return <TBlockScopeNode> node.parentNode;
  67. }
  68. if (!Utils.arrayContains(NodeUtils.scopeNodes, node.parentNode.type)) {
  69. return NodeUtils.getBlockScopeOfNode(node.parentNode, depth);
  70. }
  71. if (depth > 0) {
  72. return NodeUtils.getBlockScopeOfNode(node.parentNode, --depth);
  73. }
  74. if (node.type !== NodeType.BlockStatement) {
  75. return NodeUtils.getBlockScopeOfNode(node.parentNode);
  76. }
  77. return <TBlockScopeNode> node; // blocks statement of scopeNodes
  78. }
  79. /**
  80. * @param bodyNode
  81. * @returns IProgramNode
  82. */
  83. public static getProgramNode (bodyNode: INode[]): IProgramNode {
  84. return {
  85. 'type': NodeType.Program,
  86. 'body': bodyNode
  87. };
  88. }
  89. /**
  90. * @param blockScopeBody
  91. * @param node
  92. * @param index
  93. */
  94. public static insertNodeAtIndex (blockScopeBody: INode[], node: INode, index: number): void {
  95. if (!NodeUtils.validateNode(node)) {
  96. return;
  97. }
  98. blockScopeBody.splice(index, 0, node);
  99. }
  100. /**
  101. * @param node
  102. * @returns {boolean}
  103. */
  104. public static isBlockStatementNode (node: INode): node is IBlockStatementNode {
  105. return node.type === NodeType.BlockStatement;
  106. }
  107. /**
  108. * @param node
  109. * @returns {boolean}
  110. */
  111. public static isIdentifierNode (node: INode): node is IIdentifierNode {
  112. return node.type === NodeType.Identifier;
  113. }
  114. /**
  115. * @param node
  116. * @returns {boolean}
  117. */
  118. public static isLiteralNode (node: INode): node is ILiteralNode {
  119. return node.type === NodeType.Literal;
  120. }
  121. /**
  122. * @param node
  123. * @returns {boolean}
  124. */
  125. public static isMemberExpressionNode (node: INode): node is IMemberExpressionNode {
  126. return node.type === NodeType.MemberExpression;
  127. }
  128. /**
  129. * @param node
  130. * @returns {boolean}
  131. */
  132. public static isNodeHasBlockScope (node: INode): node is TBlockScopeNode {
  133. return node.hasOwnProperty('body');
  134. }
  135. /**
  136. *
  137. * @param node
  138. * @returns {boolean}
  139. */
  140. public static isProgramNode (node: INode): node is IProgramNode {
  141. return node.type === NodeType.Program;
  142. }
  143. /**
  144. *
  145. * @param node
  146. * @returns {boolean}
  147. */
  148. public static isPropertyNode (node: INode): node is IPropertyNode {
  149. return node.type === NodeType.Property;
  150. }
  151. /**
  152. *
  153. * @param node
  154. * @returns {boolean}
  155. */
  156. public static isVariableDeclaratorNode (node: INode): node is IVariableDeclaratorNode {
  157. return node.type === NodeType.VariableDeclarator;
  158. }
  159. /**
  160. * @param node
  161. */
  162. public static parentize (node: INode): void {
  163. let isRootNode: boolean = true;
  164. estraverse.replace(node, {
  165. enter: (node: INode, parentNode: INode): any => {
  166. Object.defineProperty(node, 'parentNode', {
  167. configurable: true,
  168. enumerable: true,
  169. value: isRootNode ? NodeUtils.getProgramNode([node]) : parentNode || node,
  170. writable: true
  171. });
  172. isRootNode = false;
  173. }
  174. });
  175. }
  176. /**
  177. * @param blockScopeBody
  178. * @param node
  179. */
  180. public static prependNode (blockScopeBody: INode[], node: INode): void {
  181. if (!NodeUtils.validateNode(node)) {
  182. return;
  183. }
  184. blockScopeBody.unshift(node);
  185. }
  186. /**
  187. * @param node
  188. * @returns {boolean}
  189. */
  190. private static validateNode (node: INode): boolean {
  191. return !!node;
  192. }
  193. }