text: /*---------------------------------------------------------------------------------------------
   *  Copyright (c) Microsoft Corporation. All rights reserved.
   *  Licensed under the MIT License. See License.txt in the project root for license information.
   *--------------------------------------------------------------------------------------------*/
  'use strict';
  import { format, isEOL } from './format.js';
  import { parseTree, findNodeAtLocation } from './parser.js';
  export function removeProperty(text, path, formattingOptions) {
      return setProperty(text, path, void 0, formattingOptions);
  }
  export function setProperty(text, originalPath, value, formattingOptions, getInsertionIndex) {
      var _a;
      var path = originalPath.slice();
      var errors = [];
      var root = parseTree(text, errors);
      var parent = void 0;
      var lastSegment = void 0;
      while (path.length > 0) {
          lastSegment = path.pop();
          parent = findNodeAtLocation(root, path);
          if (parent === void 0 && value !== void 0) {
              if (typeof lastSegment === 'string') {
                  value = (_a = {}, _a[lastSegment] = value, _a);
              }
              else {
                  value = [value];
              }
          }
          else {
              break;
          }
      }
      if (!parent) {
          // empty document
          if (value === void 0) { // delete
              throw new Error('Can not delete in empty document');
          }
          return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, formattingOptions);
      }
      else if (parent.type === 'object' && typeof lastSegment === 'string' && Array.isArray(parent.children)) {
          var existing = findNodeAtLocation(parent, [lastSegment]);
          if (existing !== void 0) {
              if (value === void 0) { // delete
                  if (!existing.parent) {
                      throw new Error('Malformed AST');
                  }
                  var propertyIndex = parent.children.indexOf(existing.parent);
                  var removeBegin = void 0;
                  var removeEnd = existing.parent.offset + existing.parent.length;
                  if (propertyIndex > 0) {
                      // remove the comma of the previous node
                      var previous = parent.children[propertyIndex - 1];
                      removeBegin = previous.offset + previous.length;
                  }
                  else {
                      removeBegin = parent.offset + 1;
                      if (parent.children.length > 1) {
                          // remove the comma of the next node
                          var next = parent.children[1];
                          removeEnd = next.offset;
                      }
                  }
                  return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: '' }, formattingOptions);
              }
              else {
                  // set value of existing property
                  return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, formattingOptions);
              }
          }
          else {
              if (value === void 0) { // delete
                  return []; // property does not exist, nothing to do
              }
              var newProperty = JSON.stringify(lastSegment) + ": " + JSON.stringify(value);
              var index = getInsertionIndex ? getInsertionIndex(parent.children.map(function (p) { return p.children[0].value; })) : parent.children.length;
              var edit = void 0;
              if (index > 0) {
                  var previous = parent.children[index - 1];
                  edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
              }
              else if (parent.children.length === 0) {
                  edit = { offset: parent.offset + 1, length: 0, content: newProperty };
              }
              else {
                  edit = { offset: parent.offset + 1, length: 0, content: newProperty + ',' };
              }
              return withFormatting(text, edit, formattingOptions);
          }
      }
      else if (parent.type === 'array' && typeof lastSegment === 'number' && Array.isArray(parent.children)) {
          var insertIndex = lastSegment;
          if (insertIndex === -1) {
              // Insert
              var newProperty = "" + JSON.stringify(value);
              var edit = void 0;
              if (parent.children.length === 0) {
                  edit = { offset: parent.offset + 1, length: 0, content: newProperty };
              }
              else {
                  var previous = parent.children[parent.children.length - 1];
                  edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
              }
              return withFormatting(text, edit, formattingOptions);
          }
          else {
              if (value === void 0 && parent.children.length >= 0) {
                  //Removal
                  var removalIndex = lastSegment;
                  var toRemove = parent.children[removalIndex];
                  var edit = void 0;
                  if (parent.children.length === 1) {
                      // only item
                      edit = { offset: parent.offset + 1, length: parent.length - 2, content: '' };
                  }
                  else if (parent.children.length - 1 === removalIndex) {
                      // last item
                      var previous = parent.children[removalIndex - 1];
                      var offset = previous.offset + previous.length;
                      var parentEndOffset = parent.offset + parent.length;
                      edit = { offset: offset, length: parentEndOffset - 2 - offset, content: '' };
                  }
                  else {
                      edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: '' };
                  }
                  return withFormatting(text, edit, formattingOptions);
              }
              else {
                  throw new Error('Array modification not supported yet');
              }
          }
      }
      else {
          throw new Error("Can not add " + (typeof lastSegment !== 'number' ? 'index' : 'property') + " to parent of type " + parent.type);
      }
  }
  function withFormatting(text, edit, formattingOptions) {
      // apply the edit
      var newText = applyEdit(text, edit);
      // format the new text
      var begin = edit.offset;
      var end = edit.offset + edit.content.length;
      if (edit.length === 0 || edit.content.length === 0) { // insert or remove
          while (begin > 0 && !isEOL(newText, begin - 1)) {
              begin--;
          }
          while (end < newText.length && !isEOL(newText, end)) {
              end++;
          }
      }
      var edits = format(newText, { offset: begin, length: end - begin }, formattingOptions);
      // apply the formatting edits and track the begin and end offsets of the changes
      for (var i = edits.length - 1; i >= 0; i--) {
          var edit_1 = edits[i];
          newText = applyEdit(newText, edit_1);
          begin = Math.min(begin, edit_1.offset);
          end = Math.max(end, edit_1.offset + edit_1.length);
          end += edit_1.content.length - edit_1.length;
      }
      // create a single edit with all changes
      var editLength = text.length - (newText.length - end) - begin;
      return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
  }
  export function applyEdit(text, edit) {
      return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
  }
  export function isWS(text, offset) {
      return '\r\n \t'.indexOf(text.charAt(offset)) !== -1;
  }
  