|
@@ -0,0 +1,57 @@
|
|
|
+import * as ESTree from 'estree';
|
|
|
+
|
|
|
+import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
|
|
|
+
|
|
|
+import { NodeGuards } from './NodeGuards';
|
|
|
+
|
|
|
+export class NodeBlockLexicalScopeUtils {
|
|
|
+ /**
|
|
|
+ * @param {Node} node
|
|
|
+ * @returns {TNodeWithLexicalScope}
|
|
|
+ */
|
|
|
+ public static getLexicalScope (node: ESTree.Node): TNodeWithLexicalScope | undefined {
|
|
|
+ return NodeBlockLexicalScopeUtils.getLexicalScopesRecursive(node, 1)[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param {Node} node
|
|
|
+ * @returns {TNodeWithLexicalScope[]}
|
|
|
+ */
|
|
|
+ public static getLexicalScopes (node: ESTree.Node): TNodeWithLexicalScope[] {
|
|
|
+ return NodeBlockLexicalScopeUtils.getLexicalScopesRecursive(node);
|
|
|
+ }
|
|
|
+
|
|
|
+ /***
|
|
|
+ * @param {Node} node
|
|
|
+ * @param {number} maxSize
|
|
|
+ * @param {TNodeWithLexicalScope[]} nodesWithLexicalScope
|
|
|
+ * @param {number} depth
|
|
|
+ * @returns {TNodeWithLexicalScope[]}
|
|
|
+ */
|
|
|
+ private static getLexicalScopesRecursive (
|
|
|
+ node: ESTree.Node,
|
|
|
+ maxSize: number = Infinity,
|
|
|
+ nodesWithLexicalScope: TNodeWithLexicalScope[] = [],
|
|
|
+ depth: number = 0
|
|
|
+ ): TNodeWithLexicalScope[] {
|
|
|
+ if (nodesWithLexicalScope.length >= maxSize) {
|
|
|
+ return nodesWithLexicalScope;
|
|
|
+ }
|
|
|
+
|
|
|
+ const parentNode: ESTree.Node | undefined = node.parentNode;
|
|
|
+
|
|
|
+ if (!parentNode) {
|
|
|
+ throw new ReferenceError('`parentNode` property of given node is `undefined`');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (NodeGuards.isNodeWithBlockLexicalScope(node)) {
|
|
|
+ nodesWithLexicalScope.push(node);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node !== parentNode) {
|
|
|
+ return NodeBlockLexicalScopeUtils.getLexicalScopesRecursive(parentNode, maxSize, nodesWithLexicalScope, ++depth);
|
|
|
+ }
|
|
|
+
|
|
|
+ return nodesWithLexicalScope;
|
|
|
+ }
|
|
|
+}
|