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