massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-json / node_modules / jsonc-parser / lib / esm / impl / edit.js
1 /*---------------------------------------------------------------------------------------------
2  *  Copyright (c) Microsoft Corporation. All rights reserved.
3  *  Licensed under the MIT License. See License.txt in the project root for license information.
4  *--------------------------------------------------------------------------------------------*/
5 'use strict';
6 import { format, isEOL } from './format';
7 import { parseTree, findNodeAtLocation } from './parser';
8 export function removeProperty(text, path, options) {
9     return setProperty(text, path, void 0, options);
10 }
11 export function setProperty(text, originalPath, value, options) {
12     var _a;
13     var path = originalPath.slice();
14     var errors = [];
15     var root = parseTree(text, errors);
16     var parent = void 0;
17     var lastSegment = void 0;
18     while (path.length > 0) {
19         lastSegment = path.pop();
20         parent = findNodeAtLocation(root, path);
21         if (parent === void 0 && value !== void 0) {
22             if (typeof lastSegment === 'string') {
23                 value = (_a = {}, _a[lastSegment] = value, _a);
24             }
25             else {
26                 value = [value];
27             }
28         }
29         else {
30             break;
31         }
32     }
33     if (!parent) {
34         // empty document
35         if (value === void 0) { // delete
36             throw new Error('Can not delete in empty document');
37         }
38         return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, options);
39     }
40     else if (parent.type === 'object' && typeof lastSegment === 'string' && Array.isArray(parent.children)) {
41         var existing = findNodeAtLocation(parent, [lastSegment]);
42         if (existing !== void 0) {
43             if (value === void 0) { // delete
44                 if (!existing.parent) {
45                     throw new Error('Malformed AST');
46                 }
47                 var propertyIndex = parent.children.indexOf(existing.parent);
48                 var removeBegin = void 0;
49                 var removeEnd = existing.parent.offset + existing.parent.length;
50                 if (propertyIndex > 0) {
51                     // remove the comma of the previous node
52                     var previous = parent.children[propertyIndex - 1];
53                     removeBegin = previous.offset + previous.length;
54                 }
55                 else {
56                     removeBegin = parent.offset + 1;
57                     if (parent.children.length > 1) {
58                         // remove the comma of the next node
59                         var next = parent.children[1];
60                         removeEnd = next.offset;
61                     }
62                 }
63                 return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: '' }, options);
64             }
65             else {
66                 // set value of existing property
67                 return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, options);
68             }
69         }
70         else {
71             if (value === void 0) { // delete
72                 return []; // property does not exist, nothing to do
73             }
74             var newProperty = JSON.stringify(lastSegment) + ": " + JSON.stringify(value);
75             var index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map(function (p) { return p.children[0].value; })) : parent.children.length;
76             var edit = void 0;
77             if (index > 0) {
78                 var previous = parent.children[index - 1];
79                 edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
80             }
81             else if (parent.children.length === 0) {
82                 edit = { offset: parent.offset + 1, length: 0, content: newProperty };
83             }
84             else {
85                 edit = { offset: parent.offset + 1, length: 0, content: newProperty + ',' };
86             }
87             return withFormatting(text, edit, options);
88         }
89     }
90     else if (parent.type === 'array' && typeof lastSegment === 'number' && Array.isArray(parent.children)) {
91         var insertIndex = lastSegment;
92         if (insertIndex === -1) {
93             // Insert
94             var newProperty = "" + JSON.stringify(value);
95             var edit = void 0;
96             if (parent.children.length === 0) {
97                 edit = { offset: parent.offset + 1, length: 0, content: newProperty };
98             }
99             else {
100                 var previous = parent.children[parent.children.length - 1];
101                 edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
102             }
103             return withFormatting(text, edit, options);
104         }
105         else if (value === void 0 && parent.children.length >= 0) {
106             // Removal
107             var removalIndex = lastSegment;
108             var toRemove = parent.children[removalIndex];
109             var edit = void 0;
110             if (parent.children.length === 1) {
111                 // only item
112                 edit = { offset: parent.offset + 1, length: parent.length - 2, content: '' };
113             }
114             else if (parent.children.length - 1 === removalIndex) {
115                 // last item
116                 var previous = parent.children[removalIndex - 1];
117                 var offset = previous.offset + previous.length;
118                 var parentEndOffset = parent.offset + parent.length;
119                 edit = { offset: offset, length: parentEndOffset - 2 - offset, content: '' };
120             }
121             else {
122                 edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: '' };
123             }
124             return withFormatting(text, edit, options);
125         }
126         else if (value !== void 0) {
127             var edit = void 0;
128             var newProperty = "" + JSON.stringify(value);
129             if (!options.isArrayInsertion && parent.children.length > lastSegment) {
130                 var toModify = parent.children[lastSegment];
131                 edit = { offset: toModify.offset, length: toModify.length, content: newProperty };
132             }
133             else if (parent.children.length === 0 || lastSegment === 0) {
134                 edit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + ',' };
135             }
136             else {
137                 var index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
138                 var previous = parent.children[index - 1];
139                 edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
140             }
141             return withFormatting(text, edit, options);
142         }
143         else {
144             throw new Error("Can not " + (value === void 0 ? 'remove' : (options.isArrayInsertion ? 'insert' : 'modify')) + " Array index " + insertIndex + " as length is not sufficient");
145         }
146     }
147     else {
148         throw new Error("Can not add " + (typeof lastSegment !== 'number' ? 'index' : 'property') + " to parent of type " + parent.type);
149     }
150 }
151 function withFormatting(text, edit, options) {
152     if (!options.formattingOptions) {
153         return [edit];
154     }
155     // apply the edit
156     var newText = applyEdit(text, edit);
157     // format the new text
158     var begin = edit.offset;
159     var end = edit.offset + edit.content.length;
160     if (edit.length === 0 || edit.content.length === 0) { // insert or remove
161         while (begin > 0 && !isEOL(newText, begin - 1)) {
162             begin--;
163         }
164         while (end < newText.length && !isEOL(newText, end)) {
165             end++;
166         }
167     }
168     var edits = format(newText, { offset: begin, length: end - begin }, options.formattingOptions);
169     // apply the formatting edits and track the begin and end offsets of the changes
170     for (var i = edits.length - 1; i >= 0; i--) {
171         var edit_1 = edits[i];
172         newText = applyEdit(newText, edit_1);
173         begin = Math.min(begin, edit_1.offset);
174         end = Math.max(end, edit_1.offset + edit_1.length);
175         end += edit_1.content.length - edit_1.length;
176     }
177     // create a single edit with all changes
178     var editLength = text.length - (newText.length - end) - begin;
179     return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
180 }
181 export function applyEdit(text, edit) {
182     return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
183 }
184 export function isWS(text, offset) {
185     return '\r\n \t'.indexOf(text.charAt(offset)) !== -1;
186 }