You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							186 lines
						
					
					
						
							8.5 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							186 lines
						
					
					
						
							8.5 KiB
						
					
					
				
								/*---------------------------------------------------------------------------------------------
							 | 
						|
								 *  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';
							 | 
						|
								import { parseTree, findNodeAtLocation } from './parser';
							 | 
						|
								export function removeProperty(text, path, options) {
							 | 
						|
								    return setProperty(text, path, void 0, options);
							 | 
						|
								}
							 | 
						|
								export function setProperty(text, originalPath, value, options) {
							 | 
						|
								    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) }, options);
							 | 
						|
								    }
							 | 
						|
								    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: '' }, options);
							 | 
						|
								            }
							 | 
						|
								            else {
							 | 
						|
								                // set value of existing property
							 | 
						|
								                return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, options);
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        else {
							 | 
						|
								            if (value === void 0) { // delete
							 | 
						|
								                return []; // property does not exist, nothing to do
							 | 
						|
								            }
							 | 
						|
								            var newProperty = JSON.stringify(lastSegment) + ": " + JSON.stringify(value);
							 | 
						|
								            var index = options.getInsertionIndex ? options.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, options);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    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, options);
							 | 
						|
								        }
							 | 
						|
								        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, options);
							 | 
						|
								        }
							 | 
						|
								        else if (value !== void 0) {
							 | 
						|
								            var edit = void 0;
							 | 
						|
								            var newProperty = "" + JSON.stringify(value);
							 | 
						|
								            if (!options.isArrayInsertion && parent.children.length > lastSegment) {
							 | 
						|
								                var toModify = parent.children[lastSegment];
							 | 
						|
								                edit = { offset: toModify.offset, length: toModify.length, content: newProperty };
							 | 
						|
								            }
							 | 
						|
								            else if (parent.children.length === 0 || lastSegment === 0) {
							 | 
						|
								                edit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + ',' };
							 | 
						|
								            }
							 | 
						|
								            else {
							 | 
						|
								                var index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
							 | 
						|
								                var previous = parent.children[index - 1];
							 | 
						|
								                edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
							 | 
						|
								            }
							 | 
						|
								            return withFormatting(text, edit, options);
							 | 
						|
								        }
							 | 
						|
								        else {
							 | 
						|
								            throw new Error("Can not " + (value === void 0 ? 'remove' : (options.isArrayInsertion ? 'insert' : 'modify')) + " Array index " + insertIndex + " as length is not sufficient");
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								        throw new Error("Can not add " + (typeof lastSegment !== 'number' ? 'index' : 'property') + " to parent of type " + parent.type);
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								function withFormatting(text, edit, options) {
							 | 
						|
								    if (!options.formattingOptions) {
							 | 
						|
								        return [edit];
							 | 
						|
								    }
							 | 
						|
								    // 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 }, options.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;
							 | 
						|
								}
							 |