text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  var tslib_1 = require("tslib");
  var errors = require("../../../errors");
  var manipulation_1 = require("../../../manipulation");
  var typescript_1 = require("../../../typescript");
  var utils_1 = require("../../../utils");
  var CommentRange_1 = require("./CommentRange");
  var Node = /** @class */ (function () {
      /**
       * Initializes a new instance.
       * @private
       * @param context - Project context.
       * @param node - Underlying node.
       * @param sourceFile - Source file for the node.
       */
      function Node(context, node, sourceFile) {
          /** @internal */
          this._wrappedChildCount = 0;
          if (context == null || context.compilerFactory == null)
              throw new errors.InvalidOperationError("Constructing a node is not supported. Please create a source file from the default export " +
                  "of the package and manipulate the source file from there.");
          this._context = context;
          this._compilerNode = node;
          this._sourceFile = sourceFile;
      }
      Object.defineProperty(Node.prototype, "compilerNode", {
          /**
           * Gets the underlying compiler node.
           */
          get: function () {
              if (this._compilerNode == null) {
                  var message = "Attempted to get information from a node that was removed or forgotten.";
                  if (this._forgottenText != null)
                      message += "\n\nNode text: " + this._forgottenText;
                  throw new errors.InvalidOperationError(message);
              }
              return this._compilerNode;
          },
          enumerable: true,
          configurable: true
      });
      /**
       * Releases the node and all its descendants from the underlying node cache and ast.
       *
       * This is useful if you want to improve the performance of manipulation by not tracking this node anymore.
       */
      Node.prototype.forget = function () {
          if (this.wasForgotten())
              return;
          this.forgetDescendants();
          this._forgetOnlyThis();
      };
      /**
       * Forgets the descendants of this node.
       */
      Node.prototype.forgetDescendants = function () {
          var e_1, _a;
          try {
              for (var _b = tslib_1.__values(this._getChildrenInCacheIterator()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var child = _c.value;
                  child.forget();
              }
          }
          catch (e_1_1) { e_1 = { error: e_1_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_1) throw e_1.error; }
          }
          return this;
      };
      /**
       * Only forgets this node.
       * @internal
       */
      Node.prototype._forgetOnlyThis = function () {
          if (this.wasForgotten())
              return;
          var parent = this.getParent();
          if (parent != null)
              parent._wrappedChildCount--;
          var parentSyntaxList = this._getParentSyntaxListIfWrapped();
          if (parentSyntaxList != null)
              parentSyntaxList._wrappedChildCount--;
          this._storeTextForForgetting();
          this._context.compilerFactory.removeNodeFromCache(this);
          this._clearInternals();
      };
      /**
       * Gets if the compiler node was forgotten.
       *
       * This will be true when the compiler node was forgotten or removed.
       */
      Node.prototype.wasForgotten = function () {
          return this._compilerNode == null;
      };
      /**
       * Gets if this node has any wrapped children.
       * @internal
       */
      Node.prototype._hasWrappedChildren = function () {
          return this._wrappedChildCount > 0;
      };
      /**
       * @internal
       *
       * WARNING: This should only be called by the compiler factory!
       */
      Node.prototype._replaceCompilerNodeFromFactory = function (compilerNode) {
          if (compilerNode == null)
              this._storeTextForForgetting();
          this._clearInternals();
          this._compilerNode = compilerNode;
      };
      /** @internal */
      Node.prototype._storeTextForForgetting = function () {
          // check for undefined here just in case
          var sourceFileCompilerNode = this._sourceFile && this._sourceFile.compilerNode;
          var compilerNode = this._compilerNode;
          if (sourceFileCompilerNode == null || compilerNode == null)
              return;
          this._forgottenText = getText();
          function getText() {
              var start = compilerNode.getStart(sourceFileCompilerNode);
              var length = compilerNode.end - start;
              var trimmedLength = Math.min(length, 100);
              var text = sourceFileCompilerNode.text.substr(start, trimmedLength);
              return trimmedLength !== length ? text + "..." : text;
          }
      };
      /** @internal */
      Node.prototype._clearInternals = function () {
          this._compilerNode = undefined;
          this._childStringRanges = undefined;
          clearCommentRanges(this._leadingCommentRanges);
          clearCommentRanges(this._trailingCommentRanges);
          this._leadingCommentRanges = undefined;
          this._trailingCommentRanges = undefined;
          function clearCommentRanges(commentRanges) {
              if (commentRanges == null)
                  return;
              commentRanges.forEach(function (r) { return r._forget(); });
          }
      };
      /**
       * Gets the syntax kind.
       */
      Node.prototype.getKind = function () {
          return this.compilerNode.kind;
      };
      /**
       * Gets the syntax kind name.
       */
      Node.prototype.getKindName = function () {
          return utils_1.getSyntaxKindName(this.compilerNode.kind);
      };
      /**
       * Prints the node using the compiler's printer.
       * @param options - Options.
       */
      Node.prototype.print = function (options) {
          if (options === void 0) { options = {}; }
          if (options.newLineKind == null)
              options.newLineKind = this._context.manipulationSettings.getNewLineKind();
          if (this.getKind() === typescript_1.SyntaxKind.SourceFile)
              return utils_1.printNode(this.compilerNode, options);
          else
              return utils_1.printNode(this.compilerNode, this._sourceFile.compilerNode, options);
      };
      /**
       * Gets the symbol or throws an error if it doesn't exist.
       */
      Node.prototype.getSymbolOrThrow = function () {
          return errors.throwIfNullOrUndefined(this.getSymbol(), "Could not find the node's symbol.");
      };
      /**
       * Gets the compiler symbol or undefined if it doesn't exist.
       */
      Node.prototype.getSymbol = function () {
          var boundSymbol = this.compilerNode.symbol;
          if (boundSymbol != null)
              return this._context.compilerFactory.getSymbol(boundSymbol);
          var typeChecker = this._context.typeChecker;
          var typeCheckerSymbol = typeChecker.getSymbolAtLocation(this);
          if (typeCheckerSymbol != null)
              return typeCheckerSymbol;
          var nameNode = this.compilerNode.name;
          if (nameNode != null)
              return this._getNodeFromCompilerNode(nameNode).getSymbol();
          return undefined;
      };
      /**
       * Gets the type of the node.
       */
      Node.prototype.getType = function () {
          return this._context.typeChecker.getTypeAtLocation(this);
      };
      /**
       * If the node contains the provided range (inclusive).
       * @param pos - Start position.
       * @param end - End position.
       */
      Node.prototype.containsRange = function (pos, end) {
          return this.getPos() <= pos && end <= this.getEnd();
      };
      /**
       * Gets if the specified position is within a string.
       * @param pos - Position.
       */
      Node.prototype.isInStringAtPos = function (pos) {
          var e_2, _a;
          errors.throwIfOutOfRange(pos, [this.getPos(), this.getEnd()], "pos");
          if (this._childStringRanges == null) {
              this._childStringRanges = [];
              try {
                  for (var _b = tslib_1.__values(this._getCompilerDescendantsIterator()), _c = _b.next(); !_c.done; _c = _b.next()) {
                      var descendant = _c.value;
                      if (utils_1.isStringKind(descendant.kind))
                          this._childStringRanges.push([descendant.getStart(this._sourceFile.compilerNode), descendant.getEnd()]);
                  }
              }
              catch (e_2_1) { e_2 = { error: e_2_1 }; }
              finally {
                  try {
                      if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                  }
                  finally { if (e_2) throw e_2.error; }
              }
          }
          var InStringRangeComparer = /** @class */ (function () {
              function InStringRangeComparer() {
              }
              InStringRangeComparer.prototype.compareTo = function (value) {
                  if (pos <= value[0])
                      return -1;
                  if (pos >= value[1] - 1)
                      return 1;
                  return 0;
              };
              return InStringRangeComparer;
          }());
          return utils_1.ArrayUtils.binarySearch(this._childStringRanges, new InStringRangeComparer()) !== -1;
      };
      Node.prototype.getFirstChildOrThrow = function (condition) {
          return errors.throwIfNullOrUndefined(this.getFirstChild(condition), "Could not find a child that matched the specified condition.");
      };
      Node.prototype.getFirstChild = function (condition) {
          var firstChild = this._getCompilerFirstChild(getWrappedCondition(this, condition));
          return this._getNodeFromCompilerNodeIfExists(firstChild);
      };
      Node.prototype.getLastChildOrThrow = function (condition) {
          return errors.throwIfNullOrUndefined(this.getLastChild(condition), "Could not find a child that matched the specified condition.");
      };
      Node.prototype.getLastChild = function (condition) {
          var lastChild = this._getCompilerLastChild(getWrappedCondition(this, condition));
          return this._getNodeFromCompilerNodeIfExists(lastChild);
      };
      Node.prototype.getFirstDescendantOrThrow = function (condition) {
          return errors.throwIfNullOrUndefined(this.getFirstDescendant(condition), "Could not find a descendant that matched the specified condition.");
      };
      Node.prototype.getFirstDescendant = function (condition) {
          var e_3, _a;
          try {
              for (var _b = tslib_1.__values(this._getDescendantsIterator()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var descendant = _c.value;
                  if (condition == null || condition(descendant))
                      return descendant;
              }
          }
          catch (e_3_1) { e_3 = { error: e_3_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_3) throw e_3.error; }
          }
          return undefined;
      };
      Node.prototype.getPreviousSiblingOrThrow = function (condition) {
          return errors.throwIfNullOrUndefined(this.getPreviousSibling(condition), "Could not find the previous sibling.");
      };
      Node.prototype.getPreviousSibling = function (condition) {
          var previousSibling = this._getCompilerPreviousSibling(getWrappedCondition(this, condition));
          return this._getNodeFromCompilerNodeIfExists(previousSibling);
      };
      Node.prototype.getNextSiblingOrThrow = function (condition) {
          return errors.throwIfNullOrUndefined(this.getNextSibling(condition), "Could not find the next sibling.");
      };
      Node.prototype.getNextSibling = function (condition) {
          var nextSibling = this._getCompilerNextSibling(getWrappedCondition(this, condition));
          return this._getNodeFromCompilerNodeIfExists(nextSibling);
      };
      /**
       * Gets the previous siblings.
       *
       * Note: Closest sibling is the zero index.
       */
      Node.prototype.getPreviousSiblings = function () {
          var _this = this;
          return this._getCompilerPreviousSiblings().map(function (n) { return _this._getNodeFromCompilerNode(n); });
      };
      /**
       * Gets the next siblings.
       *
       * Note: Closest sibling is the zero index.
       */
      Node.prototype.getNextSiblings = function () {
          var _this = this;
          return this._getCompilerNextSiblings().map(function (n) { return _this._getNodeFromCompilerNode(n); });
      };
      /**
       * Gets all the children of the node.
       */
      Node.prototype.getChildren = function () {
          var _this = this;
          return this._getCompilerChildren().map(function (n) { return _this._getNodeFromCompilerNode(n); });
      };
      /**
       * Gets the child at the specified index.
       * @param index - Index of the child.
       */
      Node.prototype.getChildAtIndex = function (index) {
          return this._getNodeFromCompilerNode(this._getCompilerChildAtIndex(index));
      };
      /**
       * @internal
       */
      Node.prototype._getChildrenIterator = function () {
          var e_4, _a, _b, _c, compilerChild, e_4_1;
          return tslib_1.__generator(this, function (_d) {
              switch (_d.label) {
                  case 0:
                      _d.trys.push([0, 5, 6, 7]);
                      _b = tslib_1.__values(this._getCompilerChildren()), _c = _b.next();
                      _d.label = 1;
                  case 1:
                      if (!!_c.done) return [3 /*break*/, 4];
                      compilerChild = _c.value;
                      return [4 /*yield*/, this._getNodeFromCompilerNode(compilerChild)];
                  case 2:
                      _d.sent();
                      _d.label = 3;
                  case 3:
                      _c = _b.next();
                      return [3 /*break*/, 1];
                  case 4: return [3 /*break*/, 7];
                  case 5:
                      e_4_1 = _d.sent();
                      e_4 = { error: e_4_1 };
                      return [3 /*break*/, 7];
                  case 6:
                      try {
                          if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                      }
                      finally { if (e_4) throw e_4.error; }
                      return [7 /*endfinally*/];
                  case 7: return [2 /*return*/];
              }
          });
      };
      /**
       * @internal
       */
      Node.prototype._getChildrenInCacheIterator = function () {
          var e_5, _a, children, children_1, children_1_1, child, e_5_1;
          return tslib_1.__generator(this, function (_b) {
              switch (_b.label) {
                  case 0:
                      children = this._getCompilerChildrenFast();
                      _b.label = 1;
                  case 1:
                      _b.trys.push([1, 8, 9, 10]);
                      children_1 = tslib_1.__values(children), children_1_1 = children_1.next();
                      _b.label = 2;
                  case 2:
                      if (!!children_1_1.done) return [3 /*break*/, 7];
                      child = children_1_1.value;
                      if (!this._context.compilerFactory.hasCompilerNode(child)) return [3 /*break*/, 4];
                      return [4 /*yield*/, this._context.compilerFactory.getExistingCompilerNode(child)];
                  case 3:
                      _b.sent();
                      return [3 /*break*/, 6];
                  case 4:
                      if (!(child.kind === typescript_1.SyntaxKind.SyntaxList)) return [3 /*break*/, 6];
                      // always return syntax lists because their children could be in the cache
                      return [4 /*yield*/, this._getNodeFromCompilerNode(child)];
                  case 5:
                      // always return syntax lists because their children could be in the cache
                      _b.sent();
                      _b.label = 6;
                  case 6:
                      children_1_1 = children_1.next();
                      return [3 /*break*/, 2];
                  case 7: return [3 /*break*/, 10];
                  case 8:
                      e_5_1 = _b.sent();
                      e_5 = { error: e_5_1 };
                      return [3 /*break*/, 10];
                  case 9:
                      try {
                          if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
                      }
                      finally { if (e_5) throw e_5.error; }
                      return [7 /*endfinally*/];
                  case 10: return [2 /*return*/];
              }
          });
      };
      /**
       * Gets the child syntax list or throws if it doesn't exist.
       */
      Node.prototype.getChildSyntaxListOrThrow = function () {
          return errors.throwIfNullOrUndefined(this.getChildSyntaxList(), "A child syntax list was expected.");
      };
      /**
       * Gets the child syntax list if it exists.
       */
      Node.prototype.getChildSyntaxList = function () {
          var e_6, _a;
          var node = this;
          if (utils_1.TypeGuards.isBodyableNode(node) || utils_1.TypeGuards.isBodiedNode(node)) {
              do {
                  var bodyNode = utils_1.TypeGuards.isBodyableNode(node) ? node.getBody() : node.getBody();
                  if (bodyNode == null)
                      return undefined;
                  node = bodyNode;
              } while ((utils_1.TypeGuards.isBodyableNode(node) || utils_1.TypeGuards.isBodiedNode(node)) && node.compilerNode.statements == null);
          }
          if (utils_1.TypeGuards.isSourceFile(node) ||
              utils_1.TypeGuards.isBodyableNode(this) ||
              utils_1.TypeGuards.isBodiedNode(this) ||
              utils_1.TypeGuards.isCaseBlock(this) ||
              utils_1.TypeGuards.isCaseClause(this) ||
              utils_1.TypeGuards.isDefaultClause(this) ||
              utils_1.TypeGuards.isJsxElement(this))
              return node.getFirstChildByKind(typescript_1.SyntaxKind.SyntaxList);
          var passedBrace = false;
          try {
              for (var _b = tslib_1.__values(node._getCompilerChildren()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var child = _c.value;
                  if (!passedBrace)
                      passedBrace = child.kind === typescript_1.SyntaxKind.OpenBraceToken;
                  else if (child.kind === typescript_1.SyntaxKind.SyntaxList)
                      return this._getNodeFromCompilerNode(child);
              }
          }
          catch (e_6_1) { e_6 = { error: e_6_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_6) throw e_6.error; }
          }
          return undefined;
      };
      /**
       * Invokes the `cbNode` callback for each child and the `cbNodeArray` for every array of nodes stored in properties of the node.
       * If `cbNodeArray` is not defined, then it will pass every element of the array to `cbNode`.
       *
       * @remarks There exists a `traversal.stop()` function on the second parameter that allows stopping iteration.
       * @param cbNode - Callback invoked for each child.
       * @param cbNodeArray - Callback invoked for each array of nodes.
       */
      Node.prototype.forEachChild = function (cbNode, cbNodeArray) {
          var _this = this;
          var e_7, _a;
          var stop = false;
          var traversal = {
              stop: function () { return stop = true; }
          };
          var snapshots = [];
          // Get all the nodes from the compiler's forEachChild. Taking this snapshot prevents the results of
          // .forEachChild from returning out of date nodes due to a manipulation or deletion
          this.compilerNode.forEachChild(function (node) {
              // use function block to ensure a truthy value is not returned
              snapshots.push(_this._getNodeFromCompilerNode(node));
          }, cbNodeArray == null ? undefined : function (nodes) {
              snapshots.push(nodes.map(function (n) { return _this._getNodeFromCompilerNode(n); }));
          });
          try {
              // now send them to the user
              for (var snapshots_1 = tslib_1.__values(snapshots), snapshots_1_1 = snapshots_1.next(); !snapshots_1_1.done; snapshots_1_1 = snapshots_1.next()) {
                  var snapshot = snapshots_1_1.value;
                  if (snapshot instanceof Array) {
                      var filteredNodes = snapshot.filter(function (n) { return !n.wasForgotten(); });
                      if (filteredNodes.length > 0)
                          cbNodeArray(filteredNodes, traversal);
                  }
                  else if (!snapshot.wasForgotten())
                      cbNode(snapshot, traversal);
                  if (stop)
                      break;
              }
          }
          catch (e_7_1) { e_7 = { error: e_7_1 }; }
          finally {
              try {
                  if (snapshots_1_1 && !snapshots_1_1.done && (_a = snapshots_1.return)) _a.call(snapshots_1);
              }
              finally { if (e_7) throw e_7.error; }
          }
      };
      /**
       * Invokes the `cbNode` callback for each descendant and the `cbNodeArray` for every array of nodes stored in properties of the node and descendant nodes.
       * If `cbNodeArray` is not defined, then it will pass every element of the array to `cbNode`.
       *
       * @remarks There exists a `traversal` object on the second parameter that allows various control of iteration.
       * @param cbNode - Callback invoked for each descendant.
       * @param cbNodeArray - Callback invoked for each array of nodes.
       */
      Node.prototype.forEachDescendant = function (cbNode, cbNodeArray) {
          var stop = false;
          var up = false;
          var traversal = {
              stop: function () { return stop = true; },
              up: function () { return up = true; }
          };
          var nodeCallback = function (node) {
              if (stop)
                  return;
              var skip = false;
              cbNode(node, tslib_1.__assign({}, traversal, { skip: function () { return skip = true; } }));
              if (stop || skip || up)
                  return;
              if (!node.wasForgotten())
                  forEachChildForNode(node);
          };
          var arrayCallback = cbNodeArray == null ? undefined : function (nodes) {
              var e_8, _a;
              if (stop)
                  return;
              var skip = false;
              cbNodeArray(nodes, tslib_1.__assign({}, traversal, { skip: function () { return skip = true; } }));
              if (skip)
                  return;
              try {
                  for (var nodes_1 = tslib_1.__values(nodes), nodes_1_1 = nodes_1.next(); !nodes_1_1.done; nodes_1_1 = nodes_1.next()) {
                      var node = nodes_1_1.value;
                      if (stop || up)
                          return;
                      forEachChildForNode(node);
                  }
              }
              catch (e_8_1) { e_8 = { error: e_8_1 }; }
              finally {
                  try {
                      if (nodes_1_1 && !nodes_1_1.done && (_a = nodes_1.return)) _a.call(nodes_1);
                  }
                  finally { if (e_8) throw e_8.error; }
              }
          };
          forEachChildForNode(this);
          function forEachChildForNode(node) {
              node.forEachChild(function (innerNode, innerTraversal) {
                  nodeCallback(innerNode);
                  if (up) {
                      innerTraversal.stop();
                      up = false;
                  }
              }, arrayCallback == null ? undefined : function (nodes, innerTraversal) {
                  arrayCallback(nodes);
                  if (up) {
                      innerTraversal.stop();
                      up = false;
                  }
              });
          }
      };
      /**
       * Gets the node's descendants.
       */
      Node.prototype.getDescendants = function () {
          return utils_1.ArrayUtils.from(this._getDescendantsIterator());
      };
      /**
       * Gets the node's descendants as an iterator.
       * @internal
       */
      Node.prototype._getDescendantsIterator = function () {
          var e_9, _a, _b, _c, descendant, e_9_1;
          return tslib_1.__generator(this, function (_d) {
              switch (_d.label) {
                  case 0:
                      _d.trys.push([0, 5, 6, 7]);
                      _b = tslib_1.__values(this._getCompilerDescendantsIterator()), _c = _b.next();
                      _d.label = 1;
                  case 1:
                      if (!!_c.done) return [3 /*break*/, 4];
                      descendant = _c.value;
                      return [4 /*yield*/, this._getNodeFromCompilerNode(descendant)];
                  case 2:
                      _d.sent();
                      _d.label = 3;
                  case 3:
                      _c = _b.next();
                      return [3 /*break*/, 1];
                  case 4: return [3 /*break*/, 7];
                  case 5:
                      e_9_1 = _d.sent();
                      e_9 = { error: e_9_1 };
                      return [3 /*break*/, 7];
                  case 6:
                      try {
                          if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                      }
                      finally { if (e_9) throw e_9.error; }
                      return [7 /*endfinally*/];
                  case 7: return [2 /*return*/];
              }
          });
      };
      /**
       * Gets the node's descendant statements.
       */
      Node.prototype.getDescendantStatements = function () {
          var statements = [];
          handleNode(this, this.compilerNode);
          return statements;
          function handleNode(thisNode, node) {
              if (handleStatements(thisNode, node))
                  return;
              else if (node.kind === typescript_1.SyntaxKind.ArrowFunction) {
                  var arrowFunction = node;
                  if (arrowFunction.body.kind !== typescript_1.SyntaxKind.Block)
                      statements.push(thisNode._getNodeFromCompilerNode(arrowFunction.body)); // todo: bug... it's not a statement
                  else
                      handleNode(thisNode, arrowFunction.body);
              }
              else
                  handleChildren(thisNode, node);
          }
          function handleStatements(thisNode, node) {
              var e_10, _a;
              if (node.statements == null)
                  return false;
              try {
                  for (var _b = tslib_1.__values(node.statements), _c = _b.next(); !_c.done; _c = _b.next()) {
                      var statement = _c.value;
                      statements.push(thisNode._getNodeFromCompilerNode(statement));
                      handleChildren(thisNode, statement);
                  }
              }
              catch (e_10_1) { e_10 = { error: e_10_1 }; }
              finally {
                  try {
                      if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                  }
                  finally { if (e_10) throw e_10.error; }
              }
              return true;
          }
          function handleChildren(thisNode, node) {
              typescript_1.ts.forEachChild(node, function (childNode) { return handleNode(thisNode, childNode); });
          }
      };
      /**
       * Gets the number of children the node has.
       */
      Node.prototype.getChildCount = function () {
          return this.compilerNode.getChildCount(this._sourceFile.compilerNode);
      };
      /**
       * Gets the child at the provided text position, or undefined if not found.
       * @param pos - Text position to search for.
       */
      Node.prototype.getChildAtPos = function (pos) {
          var e_11, _a;
          if (pos < this.getPos() || pos >= this.getEnd())
              return undefined;
          try {
              for (var _b = tslib_1.__values(this._getCompilerChildren()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var child = _c.value;
                  if (pos >= child.pos && pos < child.end)
                      return this._getNodeFromCompilerNode(child);
              }
          }
          catch (e_11_1) { e_11 = { error: e_11_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_11) throw e_11.error; }
          }
          return undefined;
      };
      /**
       * Gets the most specific descendant at the provided text position, or undefined if not found.
       * @param pos - Text position to search for.
       */
      Node.prototype.getDescendantAtPos = function (pos) {
          var node;
          while (true) {
              var nextNode = (node || this).getChildAtPos(pos);
              if (nextNode == null)
                  return node;
              else
                  node = nextNode;
          }
      };
      /**
       * Gets the most specific descendant at the provided start text position with the specified width, or undefined if not found.
       * @param start - Start text position to search for.
       * @param width - Text length of the node to search for.
       */
      Node.prototype.getDescendantAtStartWithWidth = function (start, width) {
          var _this = this;
          var foundNode;
          this._context.compilerFactory.forgetNodesCreatedInBlock(function (remember) {
              var nextNode = _this.getSourceFile();
              do {
                  nextNode = nextNode.getChildAtPos(start);
                  if (nextNode != null) {
                      if (nextNode.getStart() === start && nextNode.getWidth() === width)
                          foundNode = nextNode;
                      else if (foundNode != null)
                          break; // no need to keep looking
                  }
              } while (nextNode != null);
              if (foundNode != null)
                  remember(foundNode);
          });
          return foundNode;
      };
      /**
       * Gets the source file text position where the node starts that includes the leading trivia (comments and whitespace).
       */
      Node.prototype.getPos = function () {
          return this.compilerNode.pos;
      };
      /**
       * Gets the source file text position where the node ends.
       *
       * @remarks This does not include the following trivia (comments and whitespace).
       */
      Node.prototype.getEnd = function () {
          return this.compilerNode.end;
      };
      /**
       * Gets the source file text position where the node starts that does not include the leading trivia (comments and whitespace).
       * @param includeJsDocComment - Whether to include the JS doc comment.
       */
      Node.prototype.getStart = function (includeJsDocComment) {
          // rare time a bool parameter will be used... it's because it's done in the ts compiler
          return this.compilerNode.getStart(this._sourceFile.compilerNode, includeJsDocComment);
      };
      /**
       * Gets the source file text position of the end of the last significant token or the start of the source file.
       */
      Node.prototype.getFullStart = function () {
          return this.compilerNode.getFullStart();
      };
      /**
       * Gets the first source file text position that is not whitespace.
       */
      Node.prototype.getNonWhitespaceStart = function () {
          var parent = this.getParent();
          var parentTakesPrecedence = parent != null
              && !utils_1.TypeGuards.isSourceFile(parent)
              && parent.getPos() === this.getPos();
          return manipulation_1.getNextNonWhitespacePos(this._sourceFile.getFullText(), parentTakesPrecedence ? this.getStart(true) : this.getPos());
      };
      /**
       * Gets the source file text position going forward the result of .getTrailingTriviaEnd() that is not whitespace.
       * @internal
       */
      Node.prototype._getTrailingTriviaNonWhitespaceEnd = function () {
          return manipulation_1.getPreviousNonWhitespacePos(this._sourceFile.getFullText(), this.getTrailingTriviaEnd());
      };
      /**
       * Gets the text length of the node without trivia.
       */
      Node.prototype.getWidth = function () {
          return this.compilerNode.getWidth(this._sourceFile.compilerNode);
      };
      /**
       * Gets the text length of the node with trivia.
       */
      Node.prototype.getFullWidth = function () {
          return this.compilerNode.getFullWidth();
      };
      /**
       * Gets the node's leading trivia's text length.
       */
      Node.prototype.getLeadingTriviaWidth = function () {
          return this.compilerNode.getLeadingTriviaWidth(this._sourceFile.compilerNode);
      };
      /**
       * Gets the text length from the end of the current node to the next significant token or new line.
       */
      Node.prototype.getTrailingTriviaWidth = function () {
          return this.getTrailingTriviaEnd() - this.getEnd();
      };
      /**
       * Gets the text position of the next significant token or new line.
       */
      Node.prototype.getTrailingTriviaEnd = function () {
          var parent = this.getParent();
          var end = this.getEnd();
          if (parent == null)
              return end;
          var parentEnd = parent.getEnd();
          if (parentEnd === end)
              return end;
          var trailingComments = this.getTrailingCommentRanges();
          var searchStart = getSearchStart();
          return manipulation_1.getNextMatchingPos(this._sourceFile.getFullText(), searchStart, function (char) { return char !== " " && char !== "\t"; });
          function getSearchStart() {
              return trailingComments.length > 0 ? trailingComments[trailingComments.length - 1].getEnd() : end;
          }
      };
      /**
       * Gets the text without leading trivia (comments and whitespace).
       * @param includeJsDocComment
       */
      Node.prototype.getText = function (includeJsDocComment) {
          if (includeJsDocComment && utils_1.TypeGuards.isJSDocableNode(this)) {
              var docs = this.getJsDocs();
              if (docs.length > 0)
                  return this._sourceFile.getFullText().substring(docs[0].getStart(), this.getEnd());
          }
          return this.compilerNode.getText(this._sourceFile.compilerNode);
      };
      /**
       * Gets the full text with leading trivia (comments and whitespace).
       */
      Node.prototype.getFullText = function () {
          return this.compilerNode.getFullText(this._sourceFile.compilerNode);
      };
      /**
       * Gets the combined modifier flags.
       */
      Node.prototype.getCombinedModifierFlags = function () {
          // todo: make this method only available on declarations in the future.
          return typescript_1.ts.getCombinedModifierFlags(this.compilerNode);
      };
      /**
       * Gets the source file.
       */
      Node.prototype.getSourceFile = function () {
          return this._sourceFile;
      };
      /**
       * Gets a compiler node property wrapped in a Node.
       * @param propertyName - Property name.
       */
      Node.prototype.getNodeProperty = function (propertyName) {
          var _this = this;
          var property = this.compilerNode[propertyName];
          if (property == null)
              return undefined;
          else if (property instanceof Array)
              return property.map(function (p) { return isNode(p) ? _this._getNodeFromCompilerNode(p) : p; });
          else if (isNode(property))
              return this._getNodeFromCompilerNode(property);
          else
              return property;
          function isNode(value) {
              return typeof value.kind === "number" && typeof value.pos === "number" && typeof value.end === "number";
          }
      };
      Node.prototype.getAncestors = function (includeSyntaxLists) {
          if (includeSyntaxLists === void 0) { includeSyntaxLists = false; }
          return utils_1.ArrayUtils.from(this._getAncestorsIterator(includeSyntaxLists));
      };
      /**
       * @internal
       */
      Node.prototype._getAncestorsIterator = function (includeSyntaxLists) {
          function getParent(node) {
              return includeSyntaxLists ? node.getParentSyntaxList() || node.getParent() : node.getParent();
          }
          var parent;
          return tslib_1.__generator(this, function (_a) {
              switch (_a.label) {
                  case 0:
                      parent = getParent(this);
                      _a.label = 1;
                  case 1:
                      if (!(parent != null)) return [3 /*break*/, 3];
                      return [4 /*yield*/, parent];
                  case 2:
                      _a.sent();
                      parent = getParent(parent);
                      return [3 /*break*/, 1];
                  case 3: return [2 /*return*/];
              }
          });
      };
      /**
       * Get the node's parent.
       */
      Node.prototype.getParent = function () {
          return this._getNodeFromCompilerNodeIfExists(this.compilerNode.parent);
      };
      /**
       * Gets the parent or throws an error if it doesn't exist.
       */
      Node.prototype.getParentOrThrow = function () {
          return errors.throwIfNullOrUndefined(this.getParent(), "Expected to find a parent.");
      };
      Node.prototype.getParentWhileOrThrow = function (condition) {
          return errors.throwIfNullOrUndefined(this.getParentWhile(condition), "The initial parent did not match the provided condition.");
      };
      Node.prototype.getParentWhile = function (condition) {
          var node = undefined;
          var nextParent = this.getParent();
          while (nextParent != null && condition(nextParent)) {
              node = nextParent;
              nextParent = nextParent.getParent();
          }
          return node;
      };
      /**
       * Goes up the parents (ancestors) of the node while the parent is the specified syntax kind.
       * Throws if the initial parent is not the specified syntax kind.
       * @param kind - Syntax kind to check for.
       */
      Node.prototype.getParentWhileKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getParentWhileKind(kind), "The initial parent was not a syntax kind of " + utils_1.getSyntaxKindName(kind) + ".");
      };
      /**
       * Goes up the parents (ancestors) of the node while the parent is the specified syntax kind.
       * Returns undefined if the initial parent is not the specified syntax kind.
       * @param kind - Syntax kind to check for.
       */
      Node.prototype.getParentWhileKind = function (kind) {
          return this.getParentWhile(function (n) { return n.getKind() === kind; });
      };
      /**
       * Gets the last token of this node. Usually this is a close brace.
       */
      Node.prototype.getLastToken = function () {
          var lastToken = this.compilerNode.getLastToken(this._sourceFile.compilerNode);
          if (lastToken == null)
              throw new errors.NotImplementedError("Not implemented scenario where the last token does not exist.");
          return this._getNodeFromCompilerNode(lastToken);
      };
      /**
       * Gets if this node is in a syntax list.
       */
      Node.prototype.isInSyntaxList = function () {
          return this.getParentSyntaxList() != null;
      };
      /**
       * Gets the parent if it's a syntax list or throws an error otherwise.
       */
      Node.prototype.getParentSyntaxListOrThrow = function () {
          return errors.throwIfNullOrUndefined(this.getParentSyntaxList(), "Expected the parent to be a syntax list.");
      };
      /**
       * Gets the parent if it's a syntax list.
       */
      Node.prototype.getParentSyntaxList = function () {
          var syntaxList = utils_1.getParentSyntaxList(this.compilerNode);
          return this._getNodeFromCompilerNodeIfExists(syntaxList);
      };
      /**
       * Gets the parent syntax list if it's been wrapped.
       * @internal
       */
      Node.prototype._getParentSyntaxListIfWrapped = function () {
          var parent = this.getParent();
          if (parent == null || !parent._hasParsedTokens())
              return undefined;
          return this.getParentSyntaxList();
      };
      /**
       * Gets the child index of this node relative to the parent.
       */
      Node.prototype.getChildIndex = function () {
          var e_12, _a;
          var parent = this.getParentSyntaxList() || this.getParentOrThrow();
          var i = 0;
          try {
              for (var _b = tslib_1.__values(parent._getCompilerChildren()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var child = _c.value;
                  if (child === this.compilerNode)
                      return i;
                  i++;
              }
          }
          catch (e_12_1) { e_12 = { error: e_12_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_12) throw e_12.error; }
          }
          /* istanbul ignore next */
          throw new errors.NotImplementedError("For some reason the child's parent did not contain the child.");
      };
      /**
       * Gets the indentation level of the current node.
       */
      Node.prototype.getIndentationLevel = function () {
          var indentationText = this._context.manipulationSettings.getIndentationText();
          return this._context.languageService.getIdentationAtPosition(this._sourceFile, this.getStart()) / indentationText.length;
      };
      /**
       * Gets the child indentation level of the current node.
       */
      Node.prototype.getChildIndentationLevel = function () {
          if (utils_1.TypeGuards.isSourceFile(this))
              return 0;
          return this.getIndentationLevel() + 1;
      };
      /**
       * Gets the indentation text.
       * @param offset - Optional number of levels of indentation to add or remove.
       */
      Node.prototype.getIndentationText = function (offset) {
          if (offset === void 0) { offset = 0; }
          return this._getIndentationTextForLevel(this.getIndentationLevel() + offset);
      };
      /**
       * Gets the next indentation level text.
       * @param offset - Optional number of levels of indentation to add or remove.
       */
      Node.prototype.getChildIndentationText = function (offset) {
          if (offset === void 0) { offset = 0; }
          return this._getIndentationTextForLevel(this.getChildIndentationLevel() + offset);
      };
      /**
       * @internal
       */
      Node.prototype._getIndentationTextForLevel = function (level) {
          return utils_1.StringUtils.repeat(this._context.manipulationSettings.getIndentationText(), level);
      };
      /**
       * Gets the position of the start of the line that this node starts on.
       * @param includeJsDocComment - Whether to include the JS doc comment or not.
       */
      Node.prototype.getStartLinePos = function (includeJsDocComment) {
          var sourceFileText = this._sourceFile.getFullText();
          return manipulation_1.getPreviousMatchingPos(sourceFileText, this.getStart(includeJsDocComment), function (char) { return char === "\n" || char === "\r"; });
      };
      /**
       * Gets the line number at the start of the node.
       * @param includeJsDocComment - Whether to include the JS doc comment or not.
       */
      Node.prototype.getStartLineNumber = function (includeJsDocComment) {
          return this._sourceFile.getLineNumberAtPos(this.getStartLinePos(includeJsDocComment));
      };
      /**
       * Gets the line number of the end of the node.
       */
      Node.prototype.getEndLineNumber = function () {
          var sourceFileText = this._sourceFile.getFullText();
          var endLinePos = manipulation_1.getPreviousMatchingPos(sourceFileText, this.getEnd(), function (char) { return char === "\n" || char === "\r"; });
          return this._sourceFile.getLineNumberAtPos(endLinePos);
      };
      /**
       * Gets if this is the first node on the current line.
       */
      Node.prototype.isFirstNodeOnLine = function () {
          var sourceFileText = this._sourceFile.getFullText();
          var startPos = this.getNonWhitespaceStart();
          for (var i = startPos - 1; i >= 0; i--) {
              var currentChar = sourceFileText[i];
              if (currentChar === " " || currentChar === "\t")
                  continue;
              if (currentChar === "\n")
                  return true;
              return false;
          }
          return true; // first node on the first line
      };
      Node.prototype.replaceWithText = function (textOrWriterFunction, writer) {
          var newText = utils_1.getTextFromStringOrWriter(writer || this._getWriterWithQueuedIndentation(), textOrWriterFunction);
          if (utils_1.TypeGuards.isSourceFile(this)) {
              this.replaceText([this.getPos(), this.getEnd()], newText);
              return this;
          }
          var parent = this.getParentSyntaxList() || this.getParentOrThrow();
          var childIndex = this.getChildIndex();
          var start = this.getStart(true);
          manipulation_1.insertIntoParentTextRange({
              parent: parent,
              insertPos: start,
              newText: newText,
              replacing: {
                  textLength: this.getEnd() - start
              }
          });
          return parent.getChildren()[childIndex];
      };
      /**
       * Prepends the specified whitespace to current node.
       * @param textOrWriterFunction - Text or writer function.
       */
      Node.prototype.prependWhitespace = function (textOrWriterFunction) {
          insertWhiteSpaceTextAtPos(this, this.getStart(true), textOrWriterFunction, "prependWhitespace");
      };
      /**
       * Appends the specified whitespace to current node.
       * @param textOrWriterFunction - Text or writer function.
       */
      Node.prototype.appendWhitespace = function (textOrWriterFunction) {
          insertWhiteSpaceTextAtPos(this, this.getEnd(), textOrWriterFunction, "appendWhitespace");
      };
      /**
       * Formats the node's text using the internal TypeScript formatting API.
       * @param settings - Format code settings.
       */
      Node.prototype.formatText = function (settings) {
          if (settings === void 0) { settings = {}; }
          var formattingEdits = this._context.languageService.getFormattingEditsForRange(this._sourceFile.getFilePath(), [this.getStart(true), this.getEnd()], settings);
          manipulation_1.replaceSourceFileTextForFormatting({
              sourceFile: this._sourceFile,
              newText: manipulation_1.getTextFromFormattingEdits(this._sourceFile, formattingEdits)
          });
      };
      /**
       * Transforms the node using the compiler api nodes and functions (experimental).
       *
       * WARNING: This will forget descendants of transformed nodes.
       * @example Increments all the numeric literals in a source file.
       * ```ts
       * sourceFile.transform(traversal => {
       *   const node = traversal.visitChildren(); // recommend always visiting the children first (post order)
       *   if (ts.isNumericLiteral(node))
       *     return ts.createNumericLiteral((parseInt(node.text, 10) + 1).toString());
       *   return node;
       * });
       * ```
       * @example Updates the class declaration node without visiting the children.
       * ```ts
       * const classDec = sourceFile.getClassOrThrow("MyClass");
       * classDec.transform(traversal => {
       *   const node = traversal.currentNode;
       *   return ts.updateClassDeclaration(node, undefined, undefined, ts.createIdentifier("MyUpdatedClass"), undefined, undefined, []);
       * });
       * ```
       */
      Node.prototype.transform = function (visitNode) {
          var compilerFactory = this._context.compilerFactory;
          var printer = typescript_1.ts.createPrinter({
              newLine: this._context.manipulationSettings.getNewLineKind(),
              removeComments: false
          });
          var transformations = [];
          var compilerSourceFile = this._sourceFile.compilerNode;
          var compilerNode = this.compilerNode;
          var transformerFactory = function (context) {
              return function (rootNode) { return innerVisit(rootNode, context); };
          };
          typescript_1.ts.transform(compilerNode, [transformerFactory], this._context.compilerOptions.get());
          manipulation_1.replaceSourceFileTextStraight({
              sourceFile: this._sourceFile,
              newText: getTransformedText()
          });
          return this;
          function innerVisit(node, context) {
              var traversal = {
                  visitChildren: function () {
                      node = typescript_1.ts.visitEachChild(node, function (child) { return innerVisit(child, context); }, context);
                      return node;
                  },
                  currentNode: node
              };
              var resultNode = visitNode(traversal);
              handleTransformation(node, resultNode);
              return resultNode;
          }
          function handleTransformation(oldNode, newNode) {
              if (oldNode === newNode)
                  return;
              var start = oldNode.getStart(compilerSourceFile, true);
              var end = oldNode.end;
              var lastTransformation = transformations[transformations.length - 1];
              // remove the last transformation if it's nested within this transformation
              if (lastTransformation != null && lastTransformation.start > start)
                  transformations.pop();
              var wrappedNode = compilerFactory.getExistingCompilerNode(oldNode);
              transformations.push({
                  start: start,
                  end: end,
                  compilerNode: newNode
              });
              // It's very difficult and expensive to tell about changes that could have happened to the descendants
              // via updating properties. For this reason, descendant nodes will always be forgotten.
              if (wrappedNode != null) {
                  if (oldNode.kind !== newNode.kind)
                      wrappedNode.forget();
                  else
                      wrappedNode.forgetDescendants();
              }
          }
          function getTransformedText() {
              var e_13, _a;
              var fileText = compilerSourceFile.getFullText();
              var finalText = "";
              var lastPos = 0;
              try {
                  for (var transformations_1 = tslib_1.__values(transformations), transformations_1_1 = transformations_1.next(); !transformations_1_1.done; transformations_1_1 = transformations_1.next()) {
                      var transform = transformations_1_1.value;
                      finalText += fileText.substring(lastPos, transform.start);
                      finalText += printer.printNode(typescript_1.ts.EmitHint.Unspecified, transform.compilerNode, compilerSourceFile);
                      lastPos = transform.end;
                  }
              }
              catch (e_13_1) { e_13 = { error: e_13_1 }; }
              finally {
                  try {
                      if (transformations_1_1 && !transformations_1_1.done && (_a = transformations_1.return)) _a.call(transformations_1);
                  }
                  finally { if (e_13) throw e_13.error; }
              }
              finalText += fileText.substring(lastPos);
              return finalText;
          }
      };
      /**
       * Gets the leading comment ranges of the current node.
       */
      Node.prototype.getLeadingCommentRanges = function () {
          return this._leadingCommentRanges || (this._leadingCommentRanges = this._getCommentsAtPos(this.getFullStart(), typescript_1.ts.getLeadingCommentRanges));
      };
      /**
       * Gets the trailing comment ranges of the current node.
       */
      Node.prototype.getTrailingCommentRanges = function () {
          return this._trailingCommentRanges || (this._trailingCommentRanges = this._getCommentsAtPos(this.getEnd(), typescript_1.ts.getTrailingCommentRanges));
      };
      /** @internal */
      Node.prototype._getCommentsAtPos = function (pos, getComments) {
          var _this = this;
          if (this.getKind() === typescript_1.SyntaxKind.SourceFile)
              return [];
          return (getComments(this._sourceFile.getFullText(), pos) || []).map(function (r) { return new CommentRange_1.CommentRange(r, _this._sourceFile); });
      };
      /**
       * Gets the children based on a kind.
       * @param kind - Syntax kind.
       */
      Node.prototype.getChildrenOfKind = function (kind) {
          var _this = this;
          return this._getCompilerChildrenOfKind(kind).map(function (c) { return _this._getNodeFromCompilerNode(c); });
      };
      /**
       * Gets the first child by syntax kind or throws an error if not found.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstChildByKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getFirstChildByKind(kind), "A child of the kind " + utils_1.getSyntaxKindName(kind) + " was expected.");
      };
      /**
       * Gets the first child by syntax kind.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstChildByKind = function (kind) {
          var child = this._getCompilerChildrenOfKind(kind)[0];
          return child == null ? undefined : this._getNodeFromCompilerNode(child);
      };
      /**
       * Gets the first child if it matches the specified syntax kind or throws an error if not found.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstChildIfKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getFirstChildIfKind(kind), "A first child of the kind " + utils_1.getSyntaxKindName(kind) + " was expected.");
      };
      /**
       * Gets the first child if it matches the specified syntax kind.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstChildIfKind = function (kind) {
          var firstChild = this._getCompilerFirstChild();
          return firstChild != null && firstChild.kind === kind ? this._getNodeFromCompilerNode(firstChild) : undefined;
      };
      /**
       * Gets the last child by syntax kind or throws an error if not found.
       * @param kind - Syntax kind.
       */
      Node.prototype.getLastChildByKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getLastChildByKind(kind), "A child of the kind " + utils_1.getSyntaxKindName(kind) + " was expected.");
      };
      /**
       * Gets the last child by syntax kind.
       * @param kind - Syntax kind.
       */
      Node.prototype.getLastChildByKind = function (kind) {
          var children = this._getCompilerChildrenOfKind(kind);
          var lastChild = children[children.length - 1];
          return this._getNodeFromCompilerNodeIfExists(lastChild);
      };
      /**
       * Gets the last child if it matches the specified syntax kind or throws an error if not found.
       * @param kind - Syntax kind.
       */
      Node.prototype.getLastChildIfKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getLastChildIfKind(kind), "A last child of the kind " + utils_1.getSyntaxKindName(kind) + " was expected.");
      };
      /**
       * Gets the last child if it matches the specified syntax kind.
       * @param kind - Syntax kind.
       */
      Node.prototype.getLastChildIfKind = function (kind) {
          var lastChild = this._getCompilerLastChild();
          return lastChild != null && lastChild.kind === kind ? this._getNodeFromCompilerNode(lastChild) : undefined;
      };
      /**
       * Gets the child at the specified index if it's the specified kind or throws an exception.
       * @param index - Child index to get.
       * @param kind - Expected kind.
       */
      Node.prototype.getChildAtIndexIfKindOrThrow = function (index, kind) {
          return errors.throwIfNullOrUndefined(this.getChildAtIndexIfKind(index, kind), "Child at index " + index + " was expected to be " + utils_1.getSyntaxKindName(kind));
      };
      /**
       * Gets the child at the specified index if it's the specified kind or returns undefined.
       * @param index - Child index to get.
       * @param kind - Expected kind.
       */
      Node.prototype.getChildAtIndexIfKind = function (index, kind) {
          var node = this._getCompilerChildAtIndex(index);
          return node.kind === kind ? this._getNodeFromCompilerNode(node) : undefined;
      };
      /**
       * Gets the previous sibiling if it matches the specified kind, or throws.
       * @param kind - Kind to check.
       */
      Node.prototype.getPreviousSiblingIfKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getPreviousSiblingIfKind(kind), "A previous sibling of kind " + utils_1.getSyntaxKindName(kind) + " was expected.");
      };
      /**
       * Gets the next sibiling if it matches the specified kind, or throws.
       * @param kind - Kind to check.
       */
      Node.prototype.getNextSiblingIfKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getNextSiblingIfKind(kind), "A next sibling of kind " + utils_1.getSyntaxKindName(kind) + " was expected.");
      };
      /**
       * Gets the previous sibling if it matches the specified kind.
       * @param kind - Kind to check.
       */
      Node.prototype.getPreviousSiblingIfKind = function (kind) {
          var previousSibling = this._getCompilerPreviousSibling();
          return previousSibling != null && previousSibling.kind === kind ? this._getNodeFromCompilerNode(previousSibling) : undefined;
      };
      /**
       * Gets the next sibling if it matches the specified kind.
       * @param kind - Kind to check.
       */
      Node.prototype.getNextSiblingIfKind = function (kind) {
          var nextSibling = this._getCompilerNextSibling();
          return nextSibling != null && nextSibling.kind === kind ? this._getNodeFromCompilerNode(nextSibling) : undefined;
      };
      /**
       * Gets the parent if it's a certain syntax kind.
       */
      Node.prototype.getParentIfKind = function (kind) {
          var parentNode = this.getParent();
          return parentNode == null || parentNode.getKind() !== kind ? undefined : parentNode;
      };
      /**
       * Gets the parent if it's a certain syntax kind of throws.
       */
      Node.prototype.getParentIfKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getParentIfKind(kind), "Expected a parent with a syntax kind of " + utils_1.getSyntaxKindName(kind) + ".");
      };
      /**
       * Gets the first ancestor by syntax kind or throws if not found.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstAncestorByKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getFirstAncestorByKind(kind), "Expected an ancestor with a syntax kind of " + utils_1.getSyntaxKindName(kind) + ".");
      };
      /**
       * Get the first ancestor by syntax kind.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstAncestorByKind = function (kind) {
          var e_14, _a;
          try {
              for (var _b = tslib_1.__values(this._getAncestorsIterator(kind === typescript_1.SyntaxKind.SyntaxList)), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var parent = _c.value;
                  if (parent.getKind() === kind)
                      return parent;
              }
          }
          catch (e_14_1) { e_14 = { error: e_14_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_14) throw e_14.error; }
          }
          return undefined;
      };
      Node.prototype.getFirstAncestorOrThrow = function (condition) {
          return errors.throwIfNullOrUndefined(this.getFirstAncestor(condition), "Expected to find an ancestor that matched the provided condition.");
      };
      Node.prototype.getFirstAncestor = function (condition) {
          var e_15, _a;
          try {
              for (var _b = tslib_1.__values(this._getAncestorsIterator(false)), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var ancestor = _c.value;
                  if (condition == null || condition(ancestor))
                      return ancestor;
              }
          }
          catch (e_15_1) { e_15 = { error: e_15_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_15) throw e_15.error; }
          }
          return undefined;
      };
      /**
       * Gets the descendants that match a specified syntax kind.
       * @param kind - Kind to check.
       */
      Node.prototype.getDescendantsOfKind = function (kind) {
          var e_16, _a;
          var descendants = [];
          try {
              for (var _b = tslib_1.__values(this._getCompilerDescendantsOfKindIterator(kind)), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var descendant = _c.value;
                  descendants.push(this._getNodeFromCompilerNode(descendant));
              }
          }
          catch (e_16_1) { e_16 = { error: e_16_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_16) throw e_16.error; }
          }
          return descendants;
      };
      /**
       * Gets the first descendant by syntax kind or throws.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstDescendantByKindOrThrow = function (kind) {
          return errors.throwIfNullOrUndefined(this.getFirstDescendantByKind(kind), "A descendant of kind " + utils_1.getSyntaxKindName(kind) + " was expected to be found.");
      };
      /**
       * Gets the first descendant by syntax kind.
       * @param kind - Syntax kind.
       */
      Node.prototype.getFirstDescendantByKind = function (kind) {
          var e_17, _a;
          try {
              for (var _b = tslib_1.__values(this._getCompilerDescendantsOfKindIterator(kind)), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var descendant = _c.value;
                  return this._getNodeFromCompilerNode(descendant);
              }
          }
          catch (e_17_1) { e_17 = { error: e_17_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_17) throw e_17.error; }
          }
          return undefined;
      };
      /**
       * Gets the compiler children of the node.
       * @internal
       */
      Node.prototype._getCompilerChildren = function () {
          return this.compilerNode.getChildren(this._sourceFile.compilerNode);
      };
      /**
       * Gets the compiler children of the node using .forEachChild
       * @internal
       */
      Node.prototype._getCompilerForEachChildren = function () {
          return utils_1.getCompilerForEachChildren(this.compilerNode);
      };
      /**
       * Gets children using forEachChildren if it has no parsed tokens, otherwise getChildren.
       * @internal
       */
      Node.prototype._getCompilerChildrenFast = function () {
          return this._hasParsedTokens() ? this._getCompilerChildren() : this._getCompilerForEachChildren();
      };
      /**
       * Gets the compiler children of the specified kind.
       * @internal
       */
      Node.prototype._getCompilerChildrenOfKind = function (kind) {
          var children = useParseTreeSearchForKind(this, kind) ? this._getCompilerForEachChildren() : this._getCompilerChildren();
          return children.filter(function (c) { return c.kind === kind; });
      };
      /**
       * Gets the node's descendant compiler nodes filtered by syntax kind, based on an iterator.
       * @internal
       */
      Node.prototype._getCompilerDescendantsOfKindIterator = function (kind) {
          var e_18, _a, e_19, _b, children, children_2, children_2_1, child, descendants, descendants_1, descendants_1_1, descendant, e_19_1, e_18_1;
          return tslib_1.__generator(this, function (_c) {
              switch (_c.label) {
                  case 0:
                      children = useParseTreeSearchForKind(this, kind) ? this._getCompilerForEachChildren() : this._getCompilerChildren();
                      _c.label = 1;
                  case 1:
                      _c.trys.push([1, 14, 15, 16]);
                      children_2 = tslib_1.__values(children), children_2_1 = children_2.next();
                      _c.label = 2;
                  case 2:
                      if (!!children_2_1.done) return [3 /*break*/, 13];
                      child = children_2_1.value;
                      if (!(child.kind === kind)) return [3 /*break*/, 4];
                      return [4 /*yield*/, child];
                  case 3:
                      _c.sent();
                      _c.label = 4;
                  case 4:
                      descendants = useParseTreeSearchForKind(child.kind, kind)
                          ? getCompilerForEachDescendantsIterator(child)
                          : getCompilerDescendantsIterator(child, this._sourceFile.compilerNode);
                      _c.label = 5;
                  case 5:
                      _c.trys.push([5, 10, 11, 12]);
                      descendants_1 = tslib_1.__values(descendants), descendants_1_1 = descendants_1.next();
                      _c.label = 6;
                  case 6:
                      if (!!descendants_1_1.done) return [3 /*break*/, 9];
                      descendant = descendants_1_1.value;
                      if (!(descendant.kind === kind)) return [3 /*break*/, 8];
                      return [4 /*yield*/, descendant];
                  case 7:
                      _c.sent();
                      _c.label = 8;
                  case 8:
                      descendants_1_1 = descendants_1.next();
                      return [3 /*break*/, 6];
                  case 9: return [3 /*break*/, 12];
                  case 10:
                      e_19_1 = _c.sent();
                      e_19 = { error: e_19_1 };
                      return [3 /*break*/, 12];
                  case 11:
                      try {
                          if (descendants_1_1 && !descendants_1_1.done && (_b = descendants_1.return)) _b.call(descendants_1);
                      }
                      finally { if (e_19) throw e_19.error; }
                      return [7 /*endfinally*/];
                  case 12:
                      children_2_1 = children_2.next();
                      return [3 /*break*/, 2];
                  case 13: return [3 /*break*/, 16];
                  case 14:
                      e_18_1 = _c.sent();
                      e_18 = { error: e_18_1 };
                      return [3 /*break*/, 16];
                  case 15:
                      try {
                          if (children_2_1 && !children_2_1.done && (_a = children_2.return)) _a.call(children_2);
                      }
                      finally { if (e_18) throw e_18.error; }
                      return [7 /*endfinally*/];
                  case 16: return [2 /*return*/];
              }
          });
      };
      /**
       * Gets the node's descendant compiler nodes as an iterator.
       * @internal
       */
      Node.prototype._getCompilerDescendantsIterator = function () {
          return getCompilerDescendantsIterator(this.compilerNode, this._sourceFile.compilerNode);
      };
      /**
       * Gets the node's for-each descendant compiler nodes as an iterator.
       * @internal
       */
      Node.prototype._getCompilerForEachDescendantsIterator = function () {
          return getCompilerForEachDescendantsIterator(this.compilerNode);
      };
      /**
       * Gets the first compiler node child that matches the condition.
       * @param condition - Condition.
       * @internal
       */
      Node.prototype._getCompilerFirstChild = function (condition) {
          var e_20, _a;
          try {
              for (var _b = tslib_1.__values(this._getCompilerChildren()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var child = _c.value;
                  if (condition == null || condition(child))
                      return child;
              }
          }
          catch (e_20_1) { e_20 = { error: e_20_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_20) throw e_20.error; }
          }
          return undefined;
      };
      /**
       * Gets the last compiler node child that matches the condition.
       * @param condition - Condition.
       * @internal
       */
      Node.prototype._getCompilerLastChild = function (condition) {
          var children = this._getCompilerChildren();
          for (var i = children.length - 1; i >= 0; i--) {
              var child = children[i];
              if (condition == null || condition(child))
                  return child;
          }
          return undefined;
      };
      /**
       * Gets the previous compiler siblings.
       *
       * Note: Closest sibling is the zero index.
       * @internal
       */
      Node.prototype._getCompilerPreviousSiblings = function () {
          var e_21, _a;
          var parent = this.getParentSyntaxList() || this.getParentOrThrow();
          var previousSiblings = [];
          try {
              for (var _b = tslib_1.__values(parent._getCompilerChildren()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var child = _c.value;
                  if (child === this.compilerNode)
                      break;
                  previousSiblings.unshift(child);
              }
          }
          catch (e_21_1) { e_21 = { error: e_21_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_21) throw e_21.error; }
          }
          return previousSiblings;
      };
      /**
       * Gets the next compiler siblings.
       *
       * Note: Closest sibling is the zero index.
       * @internal
       */
      Node.prototype._getCompilerNextSiblings = function () {
          var e_22, _a;
          var foundChild = false;
          var parent = this.getParentSyntaxList() || this.getParentOrThrow();
          var nextSiblings = [];
          try {
              for (var _b = tslib_1.__values(parent._getCompilerChildren()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var child = _c.value;
                  if (!foundChild) {
                      foundChild = child === this.compilerNode;
                      continue;
                  }
                  nextSiblings.push(child);
              }
          }
          catch (e_22_1) { e_22 = { error: e_22_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_22) throw e_22.error; }
          }
          return nextSiblings;
      };
      /**
       * Gets the previous compiler sibling.
       * @param condition - Optional condition for getting the previous sibling.
       * @internal
       */
      Node.prototype._getCompilerPreviousSibling = function (condition) {
          var e_23, _a;
          try {
              for (var _b = tslib_1.__values(this._getCompilerPreviousSiblings()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var sibling = _c.value;
                  if (condition == null || condition(sibling))
                      return sibling;
              }
          }
          catch (e_23_1) { e_23 = { error: e_23_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_23) throw e_23.error; }
          }
          return undefined;
      };
      /**
       * Gets the next compiler sibling.
       * @param condition - Optional condition for getting the previous sibling.
       * @internal
       */
      Node.prototype._getCompilerNextSibling = function (condition) {
          var e_24, _a;
          try {
              for (var _b = tslib_1.__values(this._getCompilerNextSiblings()), _c = _b.next(); !_c.done; _c = _b.next()) {
                  var sibling = _c.value;
                  if (condition == null || condition(sibling))
                      return sibling;
              }
          }
          catch (e_24_1) { e_24 = { error: e_24_1 }; }
          finally {
              try {
                  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
              }
              finally { if (e_24) throw e_24.error; }
          }
          return undefined;
      };
      /**
       * Gets the compiler child at the specified index.
       * @param index - Index.
       * @internal
       */
      Node.prototype._getCompilerChildAtIndex = function (index) {
          var children = this._getCompilerChildren();
          errors.throwIfOutOfRange(index, [0, children.length - 1], "index");
          return children[index];
      };
      /**
       * Gets a writer with the indentation text.
       * @internal
       */
      Node.prototype._getWriterWithIndentation = function () {
          var writer = this._getWriter();
          writer.setIndentationLevel(this.getIndentationLevel());
          return writer;
      };
      /**
       * Gets a writer with the queued indentation text.
       * @internal
       */
      Node.prototype._getWriterWithQueuedIndentation = function () {
          var writer = this._getWriter();
          writer.queueIndentationLevel(this.getIndentationLevel());
          return writer;
      };
      /**
       * Gets a writer with the child indentation text.
       * @internal
       */
      Node.prototype._getWriterWithChildIndentation = function () {
          var writer = this._getWriter();
          writer.setIndentationLevel(this.getChildIndentationLevel());
          return writer;
      };
      /**
       * Gets a writer with the queued child indentation text.
       * @internal
       */
      Node.prototype._getWriterWithQueuedChildIndentation = function () {
          var writer = this._getWriter();
          writer.queueIndentationLevel(this.getChildIndentationLevel());
          return writer;
      };
      /** @internal */
      Node.prototype._getTextWithQueuedChildIndentation = function (textOrWriterFunc) {
          var writer = this._getWriterWithQueuedChildIndentation();
          if (typeof textOrWriterFunc === "string")
              writer.write(textOrWriterFunc);
          else
              textOrWriterFunc(writer);
          return writer.toString();
      };
      /**
       * Gets a writer with no child indentation text.
       * @internal
       */
      Node.prototype._getWriter = function () {
          return this._context.createWriter();
      };
      /**
       * Gets or creates a node from the internal cache.
       * @internal
       */
      Node.prototype._getNodeFromCompilerNode = function (compilerNode) {
          return this._context.compilerFactory.getNodeFromCompilerNode(compilerNode, this._sourceFile);
      };
      /**
       * Gets or creates a node from the internal cache, if it exists.
       * @internal
       */
      Node.prototype._getNodeFromCompilerNodeIfExists = function (compilerNode) {
          return compilerNode == null ? undefined : this._getNodeFromCompilerNode(compilerNode);
      };
      /**
       * Gets if this node has previously parsed tokens.
       * @internal
       */
      Node.prototype._hasParsedTokens = function () {
          // if this is true, it means the compiler has previously parsed the tokens
          return this.compilerNode._children != null;
      };
      /**
       * Ensures that the binder has bound the node before.
       * @internal
       */
      Node.prototype._ensureBound = function () {
          if (this.compilerNode.symbol != null)
              return;
          this.getSymbol(); // binds the node
      };
      return Node;
  }());
  exports.Node = Node;
  function getWrappedCondition(thisNode, condition) {
      return condition == null ? undefined : (function (c) { return condition(thisNode._getNodeFromCompilerNode(c)); });
  }
  function insertWhiteSpaceTextAtPos(node, insertPos, textOrWriterFunction, methodName) {
      var parent = utils_1.TypeGuards.isSourceFile(node) ? node.getChildSyntaxListOrThrow() : node.getParentSyntaxList() || node.getParentOrThrow();
      var newText = utils_1.getTextFromStringOrWriter(node._getWriterWithQueuedIndentation(), textOrWriterFunction);
      if (!/^[\s\r\n]*$/.test(newText))
          throw new errors.InvalidOperationError("Cannot insert non-whitespace into " + methodName + ".");
      manipulation_1.insertIntoParentTextRange({
          parent: parent,
          insertPos: insertPos,
          newText: newText
      });
  }
  function getCompilerForEachDescendantsIterator(node) {
      function getForEachChildren() {
          var children = [];
          node.forEachChild(function (child) {
              children.push(child);
          });
          return children;
      }
      var e_25, _a, _b, _c, child, e_25_1;
      return tslib_1.__generator(this, function (_d) {
          switch (_d.label) {
              case 0:
                  _d.trys.push([0, 6, 7, 8]);
                  _b = tslib_1.__values(getForEachChildren()), _c = _b.next();
                  _d.label = 1;
              case 1:
                  if (!!_c.done) return [3 /*break*/, 5];
                  child = _c.value;
                  return [4 /*yield*/, child];
              case 2:
                  _d.sent();
                  return [5 /*yield**/, tslib_1.__values(getCompilerForEachDescendantsIterator(child))];
              case 3:
                  _d.sent();
                  _d.label = 4;
              case 4:
                  _c = _b.next();
                  return [3 /*break*/, 1];
              case 5: return [3 /*break*/, 8];
              case 6:
                  e_25_1 = _d.sent();
                  e_25 = { error: e_25_1 };
                  return [3 /*break*/, 8];
              case 7:
                  try {
                      if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                  }
                  finally { if (e_25) throw e_25.error; }
                  return [7 /*endfinally*/];
              case 8: return [2 /*return*/];
          }
      });
  }
  function getCompilerDescendantsIterator(node, sourceFile) {
      var e_26, _a, _b, _c, child, e_26_1;
      return tslib_1.__generator(this, function (_d) {
          switch (_d.label) {
              case 0:
                  _d.trys.push([0, 6, 7, 8]);
                  _b = tslib_1.__values(node.getChildren(sourceFile)), _c = _b.next();
                  _d.label = 1;
              case 1:
                  if (!!_c.done) return [3 /*break*/, 5];
                  child = _c.value;
                  return [4 /*yield*/, child];
              case 2:
                  _d.sent();
                  return [5 /*yield**/, tslib_1.__values(getCompilerDescendantsIterator(child, sourceFile))];
              case 3:
                  _d.sent();
                  _d.label = 4;
              case 4:
                  _c = _b.next();
                  return [3 /*break*/, 1];
              case 5: return [3 /*break*/, 8];
              case 6:
                  e_26_1 = _d.sent();
                  e_26 = { error: e_26_1 };
                  return [3 /*break*/, 8];
              case 7:
                  try {
                      if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                  }
                  finally { if (e_26) throw e_26.error; }
                  return [7 /*endfinally*/];
              case 8: return [2 /*return*/];
          }
      });
  }
  /**
   * Tells the calling code if it's safe to search for the specified kind
   * using only the ast (`node.forEachChild(...)`... much faster) instead
   * of having to parse all the tokens via `node.getChildren()`.
   */
  function useParseTreeSearchForKind(thisNodeOrSyntaxKind, searchingKind) {
      return searchingKind >= typescript_1.SyntaxKind.FirstNode && searchingKind < typescript_1.SyntaxKind.FirstJSDocNode
          && getThisKind() !== typescript_1.SyntaxKind.SyntaxList;
      function getThisKind() {
          if (typeof thisNodeOrSyntaxKind === "number")
              return thisNodeOrSyntaxKind;
          return thisNodeOrSyntaxKind.compilerNode.kind;
      }
  }
  