summaryrefslogtreecommitdiff
path: root/node_modules/jsonc-parser/lib/esm/impl/edit.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/jsonc-parser/lib/esm/impl/edit.js')
-rw-r--r--node_modules/jsonc-parser/lib/esm/impl/edit.js185
1 files changed, 185 insertions, 0 deletions
diff --git a/node_modules/jsonc-parser/lib/esm/impl/edit.js b/node_modules/jsonc-parser/lib/esm/impl/edit.js
new file mode 100644
index 0000000..4114d52
--- /dev/null
+++ b/node_modules/jsonc-parser/lib/esm/impl/edit.js
@@ -0,0 +1,185 @@
+/*---------------------------------------------------------------------------------------------
+ * 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) {
+ const path = originalPath.slice();
+ const errors = [];
+ const root = parseTree(text, errors);
+ let parent = void 0;
+ let 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 = { [lastSegment]: value };
+ }
+ 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)) {
+ const existing = findNodeAtLocation(parent, [lastSegment]);
+ if (existing !== void 0) {
+ if (value === void 0) { // delete
+ if (!existing.parent) {
+ throw new Error('Malformed AST');
+ }
+ const propertyIndex = parent.children.indexOf(existing.parent);
+ let removeBegin;
+ let removeEnd = existing.parent.offset + existing.parent.length;
+ if (propertyIndex > 0) {
+ // remove the comma of the previous node
+ let 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
+ let 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
+ }
+ const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
+ const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map(p => p.children[0].value)) : parent.children.length;
+ let edit;
+ if (index > 0) {
+ let 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)) {
+ const insertIndex = lastSegment;
+ if (insertIndex === -1) {
+ // Insert
+ const newProperty = `${JSON.stringify(value)}`;
+ let edit;
+ if (parent.children.length === 0) {
+ edit = { offset: parent.offset + 1, length: 0, content: newProperty };
+ }
+ else {
+ const 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
+ const removalIndex = lastSegment;
+ const toRemove = parent.children[removalIndex];
+ let edit;
+ 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
+ let previous = parent.children[removalIndex - 1];
+ let offset = previous.offset + previous.length;
+ let parentEndOffset = parent.offset + parent.length;
+ edit = { 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) {
+ let edit;
+ const newProperty = `${JSON.stringify(value)}`;
+ if (!options.isArrayInsertion && parent.children.length > lastSegment) {
+ const 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 {
+ const index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
+ const 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
+ let newText = applyEdit(text, edit);
+ // format the new text
+ let begin = edit.offset;
+ let 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++;
+ }
+ }
+ const edits = format(newText, { offset: begin, length: end - begin }, { ...options.formattingOptions, keepLines: false });
+ // apply the formatting edits and track the begin and end offsets of the changes
+ for (let i = edits.length - 1; i >= 0; i--) {
+ const edit = edits[i];
+ newText = applyEdit(newText, edit);
+ begin = Math.min(begin, edit.offset);
+ end = Math.max(end, edit.offset + edit.length);
+ end += edit.content.length - edit.length;
+ }
+ // create a single edit with all changes
+ const 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;
+}