NodeGuards.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /* eslint-disable max-lines */
  2. import * as ESTree from 'estree';
  3. import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
  4. import { TNodeWithLexicalScopeStatements } from '../types/node/TNodeWithLexicalScopeStatements';
  5. import { TNodeWithSingleStatementBody } from '../types/node/TNodeWithSingleStatementBody';
  6. import { TNodeWithStatements } from '../types/node/TNodeWithStatements';
  7. import { NodeType } from '../enums/node/NodeType';
  8. export class NodeGuards {
  9. /**
  10. * @type {string[]}
  11. */
  12. private static readonly nodesWithLexicalStatements: string[] = [
  13. NodeType.ArrowFunctionExpression,
  14. NodeType.FunctionDeclaration,
  15. NodeType.FunctionExpression,
  16. NodeType.MethodDefinition,
  17. ];
  18. /**
  19. * @param {Node} node
  20. * @returns {boolean}
  21. */
  22. public static isArrayPatternNode (node: ESTree.Node): node is ESTree.ArrayPattern {
  23. return node.type === NodeType.ArrayPattern;
  24. }
  25. /**
  26. * @param {Node} node
  27. * @returns {boolean}
  28. */
  29. public static isArrowFunctionExpressionNode (node: ESTree.Node): node is ESTree.ArrowFunctionExpression {
  30. return node.type === NodeType.ArrowFunctionExpression;
  31. }
  32. /**
  33. * @param {Node} node
  34. * @returns {boolean}
  35. */
  36. public static isAssignmentExpressionNode (node: ESTree.Node): node is ESTree.AssignmentExpression {
  37. return node.type === NodeType.AssignmentExpression;
  38. }
  39. /**
  40. * @param {Node} node
  41. * @returns {boolean}
  42. */
  43. public static isAssignmentPatternNode (node: ESTree.Node): node is ESTree.AssignmentPattern {
  44. return node.type === NodeType.AssignmentPattern;
  45. }
  46. /**
  47. * @param {Node} node
  48. * @returns {boolean}
  49. */
  50. public static isAwaitExpressionNode (node: ESTree.Node): node is ESTree.AwaitExpression {
  51. return node.type === NodeType.AwaitExpression;
  52. }
  53. /**
  54. * @param {Node} node
  55. * @returns {boolean}
  56. */
  57. public static isBigIntLiteralNode (node: ESTree.Node): node is ESTree.BigIntLiteral {
  58. return NodeGuards.isLiteralNode(node) && !!(<ESTree.BigIntLiteral>node).bigint;
  59. }
  60. /**
  61. * @param {Node} node
  62. * @returns {boolean}
  63. */
  64. public static isBlockStatementNode (node: ESTree.Node): node is ESTree.BlockStatement {
  65. return node.type === NodeType.BlockStatement;
  66. }
  67. /**
  68. * @param {Node} node
  69. * @returns {boolean}
  70. */
  71. public static isBreakStatementNode (node: ESTree.Node): node is ESTree.BreakStatement {
  72. return node.type === NodeType.BreakStatement;
  73. }
  74. /**
  75. * @param {Node} node
  76. * @returns {boolean}
  77. */
  78. public static isCallExpressionNode (node: ESTree.Node): node is ESTree.CallExpression {
  79. return node.type === NodeType.CallExpression;
  80. }
  81. /**
  82. * @param {Node} node
  83. * @returns {boolean}
  84. */
  85. public static isClassBodyNode (
  86. node: ESTree.Node
  87. ): node is ESTree.ClassBody {
  88. return node.type === NodeType.ClassBody;
  89. }
  90. /**
  91. * @param {Node} node
  92. * @returns {boolean}
  93. */
  94. public static isClassDeclarationNode (
  95. node: ESTree.Node
  96. ): node is ESTree.ClassDeclaration & { id: ESTree.Identifier } {
  97. return node.type === NodeType.ClassDeclaration && node.id !== null;
  98. }
  99. /**
  100. * @param {Node} node
  101. * @returns {boolean}
  102. */
  103. public static isConditionalExpressionNode (node: ESTree.Node): node is ESTree.ConditionalExpression {
  104. return node.type === NodeType.ConditionalExpression;
  105. }
  106. /**
  107. * @param {Node} node
  108. * @returns {boolean}
  109. */
  110. public static isContinueStatementNode (node: ESTree.Node): node is ESTree.ContinueStatement {
  111. return node.type === NodeType.ContinueStatement;
  112. }
  113. /**
  114. * @param {Node} node
  115. * @returns {boolean}
  116. */
  117. public static isDirectiveNode (node: ESTree.Node): node is ESTree.Directive {
  118. return node.type === NodeType.ExpressionStatement
  119. && 'directive' in node;
  120. }
  121. /**
  122. * @param {Node} node
  123. * @returns {boolean}
  124. */
  125. public static isDoWhileStatementNode (node: ESTree.Node): node is ESTree.DoWhileStatement {
  126. return node.type === NodeType.DoWhileStatement;
  127. }
  128. /**
  129. * @param {Node} node
  130. * @returns {boolean}
  131. */
  132. public static isExportAllDeclarationNode (node: ESTree.Node): node is ESTree.ExportAllDeclaration {
  133. return node.type === NodeType.ExportAllDeclaration;
  134. }
  135. /**
  136. * @param {Node} node
  137. * @returns {boolean}
  138. */
  139. public static isExportNamedDeclarationNode (node: ESTree.Node): node is ESTree.ExportNamedDeclaration {
  140. return node.type === NodeType.ExportNamedDeclaration;
  141. }
  142. /**
  143. * @param {Node} node
  144. * @returns {boolean}
  145. */
  146. public static isExportSpecifierNode (node: ESTree.Node): node is ESTree.ExportSpecifier {
  147. return node.type === NodeType.ExportSpecifier;
  148. }
  149. /**
  150. * @param {Node} node
  151. * @returns {boolean}
  152. */
  153. public static isExpressionStatementNode (node: ESTree.Node): node is ESTree.ExpressionStatement {
  154. return node.type === NodeType.ExpressionStatement
  155. && !('directive' in node);
  156. }
  157. /**
  158. * @param {Node} node
  159. * @returns {boolean}
  160. */
  161. public static isForStatementNode (node: ESTree.Node): node is ESTree.ForStatement {
  162. return node.type === NodeType.ForStatement;
  163. }
  164. /**
  165. * @param {Node} node
  166. * @returns {boolean}
  167. */
  168. public static isForInStatementNode (node: ESTree.Node): node is ESTree.ForInStatement {
  169. return node.type === NodeType.ForInStatement;
  170. }
  171. /**
  172. * @param {Node} node
  173. * @returns {boolean}
  174. */
  175. public static isForOfStatementNode (node: ESTree.Node): node is ESTree.ForOfStatement {
  176. return node.type === NodeType.ForOfStatement;
  177. }
  178. /**
  179. * @param {Node} node
  180. * @returns {boolean}
  181. */
  182. public static isFunctionNode (node: ESTree.Node): node is ESTree.Function {
  183. return NodeGuards.isFunctionDeclarationNode(node) ||
  184. NodeGuards.isFunctionExpressionNode(node) ||
  185. NodeGuards.isArrowFunctionExpressionNode(node);
  186. }
  187. /**
  188. * @param {Node} node
  189. * @returns {boolean}
  190. */
  191. public static isFunctionDeclarationNode (
  192. node: ESTree.Node
  193. ): node is ESTree.FunctionDeclaration & { id: ESTree.Identifier } {
  194. return node.type === NodeType.FunctionDeclaration && node.id !== null;
  195. }
  196. /**
  197. * @param {Node} node
  198. * @returns {boolean}
  199. */
  200. public static isFunctionExpressionNode (node: ESTree.Node): node is ESTree.FunctionExpression {
  201. return node.type === NodeType.FunctionExpression;
  202. }
  203. /**
  204. * @param {Node} node
  205. * @returns {boolean}
  206. */
  207. public static isIdentifierNode (node: ESTree.Node): node is ESTree.Identifier {
  208. return node.type === NodeType.Identifier;
  209. }
  210. /**
  211. * @param {Node} node
  212. * @returns {boolean}
  213. */
  214. public static isIfStatementNode (node: ESTree.Node): node is ESTree.IfStatement {
  215. return node.type === NodeType.IfStatement;
  216. }
  217. /**
  218. * @param {Node} node
  219. * @returns {boolean}
  220. */
  221. public static isIfStatementNodeWithSingleStatementBody (node: ESTree.Node): node is ESTree.IfStatement {
  222. if (!NodeGuards.isIfStatementNode(node)) {
  223. return false;
  224. }
  225. return !NodeGuards.isBlockStatementNode(node.consequent)
  226. || (!!node.alternate && !NodeGuards.isBlockStatementNode(node.alternate));
  227. }
  228. /**
  229. * @param {Node} node
  230. * @returns {boolean}
  231. */
  232. public static isImportDeclarationNode (node: ESTree.Node): node is ESTree.ImportDeclaration {
  233. return node.type === NodeType.ImportDeclaration;
  234. }
  235. /**
  236. * @param {Node} node
  237. * @returns {boolean}
  238. */
  239. public static isImportSpecifierNode (node: ESTree.Node): node is ESTree.ImportSpecifier {
  240. return node.type === NodeType.ImportSpecifier;
  241. }
  242. /**
  243. * @param {Node} node
  244. * @param {Node} parentNode
  245. * @returns {boolean}
  246. */
  247. public static isLabelIdentifierNode (node: ESTree.Node, parentNode: ESTree.Node): node is ESTree.Identifier {
  248. const parentNodeIsLabeledStatementNode: boolean = NodeGuards.isLabeledStatementNode(parentNode) && parentNode.label === node;
  249. const parentNodeIsContinueStatementNode: boolean = NodeGuards.isContinueStatementNode(parentNode) && parentNode.label === node;
  250. const parentNodeIsBreakStatementNode: boolean = NodeGuards.isBreakStatementNode(parentNode) && parentNode.label === node;
  251. return parentNodeIsLabeledStatementNode || parentNodeIsContinueStatementNode || parentNodeIsBreakStatementNode;
  252. }
  253. /**
  254. * @param {Node} node
  255. * @returns {boolean}
  256. */
  257. public static isLabeledStatementNode (node: ESTree.Node): node is ESTree.LabeledStatement {
  258. return node.type === NodeType.LabeledStatement;
  259. }
  260. /**
  261. * @param {Node} node
  262. * @returns {boolean}
  263. */
  264. public static isLiteralNode (node: ESTree.Node): node is ESTree.Literal {
  265. return node.type === NodeType.Literal;
  266. }
  267. /**
  268. * @param {Node} node
  269. * @returns {boolean}
  270. */
  271. public static isLogicalExpressionNode (node: ESTree.Node): node is ESTree.LogicalExpression {
  272. return node.type === NodeType.LogicalExpression;
  273. }
  274. /**
  275. * @param {Node} node
  276. * @returns {boolean}
  277. */
  278. public static isMemberExpressionNode (node: ESTree.Node): node is ESTree.MemberExpression {
  279. return node.type === NodeType.MemberExpression;
  280. }
  281. /**
  282. * @param {Node} node
  283. * @returns {boolean}
  284. */
  285. public static isMethodDefinitionNode (node: ESTree.Node): node is ESTree.MethodDefinition {
  286. return node.type === NodeType.MethodDefinition;
  287. }
  288. /**
  289. * @param {Node} node
  290. * @returns {boolean}
  291. */
  292. public static isNewExpressionNode (node: ESTree.Node): node is ESTree.NewExpression {
  293. return node.type === NodeType.NewExpression;
  294. }
  295. /**
  296. * @param {Object} object
  297. * @returns {boolean}
  298. */
  299. // eslint-disable-next-line @typescript-eslint/ban-types
  300. public static isNode (object: Object & { type?: string }): object is ESTree.Node {
  301. return object && !object.type !== undefined;
  302. }
  303. /**
  304. * @param {Node} node
  305. * @returns {boolean}
  306. */
  307. public static isNodeWithLexicalScope (node: ESTree.Node): node is TNodeWithLexicalScope {
  308. return NodeGuards.isProgramNode(node) || NodeGuards.isFunctionNode(node);
  309. }
  310. /**
  311. * @param {Node} node
  312. * @returns {boolean}
  313. */
  314. public static isNodeWithBlockLexicalScope (node: ESTree.Node): node is TNodeWithLexicalScope {
  315. return NodeGuards.isNodeWithLexicalScope(node) || NodeGuards.isBlockStatementNode(node);
  316. }
  317. /**
  318. * Checks if a node is the node with single statement body, like:
  319. * while (true)
  320. * console.log(1);
  321. *
  322. * or:
  323. *
  324. *
  325. * @param {Node} node
  326. * @returns {boolean}
  327. */
  328. public static isNodeWithSingleStatementBody (node: ESTree.Node): node is TNodeWithSingleStatementBody {
  329. // Different approach for `IfStatement` node because this node hasn't `body` property
  330. if (NodeGuards.isIfStatementNode(node)) {
  331. return NodeGuards.isIfStatementNodeWithSingleStatementBody(node);
  332. }
  333. // All other nodes with `Statement` node as `body` property
  334. return (
  335. NodeGuards.isForStatementNode(node)
  336. || NodeGuards.isForOfStatementNode(node)
  337. || NodeGuards.isForInStatementNode(node)
  338. || NodeGuards.isWhileStatementNode(node)
  339. || NodeGuards.isDoWhileStatementNode(node)
  340. || NodeGuards.isWithStatementNode(node)
  341. || NodeGuards.isLabeledStatementNode(node)
  342. ) && !NodeGuards.isBlockStatementNode(node.body);
  343. }
  344. /**
  345. * @param {Node} node
  346. * @param {Node} parentNode
  347. * @returns {boolean}
  348. */
  349. public static isNodeWithLexicalScopeStatements (
  350. node: ESTree.Node,
  351. parentNode: ESTree.Node
  352. ): node is TNodeWithLexicalScopeStatements {
  353. return NodeGuards.isProgramNode(node)
  354. || (NodeGuards.isBlockStatementNode(node) && NodeGuards.nodesWithLexicalStatements.includes(parentNode.type));
  355. }
  356. /**
  357. * @param {Node} node
  358. * @returns {boolean}
  359. */
  360. public static isNodeWithStatements (node: ESTree.Node): node is TNodeWithStatements {
  361. return NodeGuards.isProgramNode(node)
  362. || NodeGuards.isBlockStatementNode(node)
  363. || NodeGuards.isSwitchCaseNode(node);
  364. }
  365. /**
  366. * @param {Node} node
  367. * @returns {boolean}
  368. */
  369. public static isNodeWithComments (node: ESTree.Node): node is ESTree.Node {
  370. return Boolean(node.leadingComments) || Boolean(node.trailingComments);
  371. }
  372. /**
  373. * @param {Node} node
  374. * @returns {boolean}
  375. */
  376. public static isObjectPatternNode (node: ESTree.Node): node is ESTree.ObjectPattern {
  377. return node.type === NodeType.ObjectPattern;
  378. }
  379. /**
  380. * @param {Node} node
  381. * @returns {boolean}
  382. */
  383. public static isObjectExpressionNode (node: ESTree.Node): node is ESTree.ObjectExpression {
  384. return node.type === NodeType.ObjectExpression;
  385. }
  386. /**
  387. * @param {Node} node
  388. * @returns {boolean}
  389. */
  390. public static isProgramNode (node: ESTree.Node): node is ESTree.Program {
  391. return node.type === NodeType.Program;
  392. }
  393. /**
  394. * @param {Node} node
  395. * @returns {boolean}
  396. */
  397. public static isPropertyNode (node: ESTree.Node): node is ESTree.Property {
  398. return node.type === NodeType.Property;
  399. }
  400. /**
  401. * @param {Node} node
  402. * @returns {boolean}
  403. */
  404. public static isPropertyDefinitionNode (node: ESTree.Node): node is ESTree.PropertyDefinition {
  405. return node.type === NodeType.PropertyDefinition;
  406. }
  407. /**
  408. * @param {Node} node
  409. * @returns {boolean}
  410. */
  411. public static isRestElementNode (node: ESTree.Node): node is ESTree.RestElement {
  412. return node.type === NodeType.RestElement;
  413. }
  414. /**
  415. * @param {Node} node
  416. * @returns {boolean}
  417. */
  418. public static isReturnStatementNode (node: ESTree.Node): node is ESTree.ReturnStatement {
  419. return node.type === NodeType.ReturnStatement;
  420. }
  421. /**
  422. * @param {Node} node
  423. * @returns {boolean}
  424. */
  425. public static isSequenceExpressionNode (node: ESTree.Node): node is ESTree.SequenceExpression {
  426. return node.type === NodeType.SequenceExpression;
  427. }
  428. /**
  429. * @param {Node} node
  430. * @returns {boolean}
  431. */
  432. public static isSpreadElementNode (node: ESTree.Node): node is ESTree.SpreadElement {
  433. return node.type === NodeType.SpreadElement;
  434. }
  435. /**
  436. * @param {Node} node
  437. * @returns {boolean}
  438. */
  439. public static isSuperNode (node: ESTree.Node): node is ESTree.Super {
  440. return node.type === NodeType.Super;
  441. }
  442. /**
  443. * @param {Node} node
  444. * @returns {boolean}
  445. */
  446. public static isSwitchCaseNode (node: ESTree.Node): node is ESTree.SwitchCase {
  447. return node.type === NodeType.SwitchCase;
  448. }
  449. /**
  450. * @param {Node} node
  451. * @returns {boolean}
  452. */
  453. public static isTaggedTemplateExpressionNode (node: ESTree.Node): node is ESTree.TaggedTemplateExpression {
  454. return node.type === NodeType.TaggedTemplateExpression;
  455. }
  456. /**
  457. * @param {Node} node
  458. * @returns {boolean}
  459. */
  460. public static isTemplateLiteralNode (node: ESTree.Node): node is ESTree.TemplateLiteral {
  461. return node.type === NodeType.TemplateLiteral;
  462. }
  463. /**
  464. * @param {Node} node
  465. * @returns {boolean}
  466. */
  467. public static isThisExpressionNode (node: ESTree.Node): node is ESTree.ThisExpression {
  468. return node.type === NodeType.ThisExpression;
  469. }
  470. /**
  471. * @param {Node} node
  472. * @returns {boolean}
  473. */
  474. public static isUnaryExpressionNode (node: ESTree.Node): node is ESTree.UnaryExpression {
  475. return node.type === NodeType.UnaryExpression;
  476. }
  477. /**
  478. * @param {Node} node
  479. * @returns {boolean}
  480. */
  481. public static isVariableDeclarationNode (node: ESTree.Node): node is ESTree.VariableDeclaration {
  482. return node.type === NodeType.VariableDeclaration;
  483. }
  484. /**
  485. * @param {Node} node
  486. * @returns {boolean}
  487. */
  488. public static isVariableDeclaratorNode (node: ESTree.Node): node is ESTree.VariableDeclarator {
  489. return node.type === NodeType.VariableDeclarator;
  490. }
  491. /**
  492. * @param {Node} node
  493. * @returns {boolean}
  494. */
  495. public static isWithStatementNode (node: ESTree.Node): node is ESTree.WithStatement {
  496. return node.type === NodeType.WithStatement;
  497. }
  498. /**
  499. * @param {Node} node
  500. * @returns {boolean}
  501. */
  502. public static isWhileStatementNode (node: ESTree.Node): node is ESTree.WhileStatement {
  503. return node.type === NodeType.WhileStatement;
  504. }
  505. /**
  506. * @param {Node} node
  507. * @returns {boolean}
  508. */
  509. public static isYieldExpressionNode (node: ESTree.Node): node is ESTree.YieldExpression {
  510. return node.type === NodeType.YieldExpression;
  511. }
  512. }