Skip to content

Commit

Permalink
replace inPlace with optional ModificationOptions.formattingOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
aeschli committed Jul 3, 2020
1 parent b905205 commit f53c7ba
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 84 deletions.
34 changes: 20 additions & 14 deletions CHANGELOG.md
@@ -1,45 +1,51 @@
2.3.0 2020-07-03
==================
* new API `ModificationOptions.isArrayInsertion`: If `JSONPath` refers to an index of an array and `isArrayInsertion` is `true`, then `modify` will insert a new item at that location instead of overwriting its contents.
* `ModificationOptions.formattingOptions` is now optional. If not set, newly inserted content will be not be formatted.


2.2.0 2019-10-25
==================
* added *ParseOptions.allowEmptyContent*. Default is `false`.
* New API *getNodeType*: Returns the type of a value returned by parse.
* parse: Fix issue with empty property name
* added `ParseOptions.allowEmptyContent`. Default is `false`.
* new API `getNodeType`: Returns the type of a value returned by parse.
* `parse`: Fix issue with empty property name

2.1.0 2019-03-29
==================
* `JSONScanner` and `JSONVisitor` return lineNumber / character.

2.0.0 2018-04-12
==================
* renamed Node.columnOffset to Node.colonOffset
* new API getNodePath: Gets the JSON path of the given JSON DOM node
* new API findNodeAtOffset: Finds the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.
* renamed `Node.columnOffset` to `Node.colonOffset`
* new API `getNodePath`: Gets the JSON path of the given JSON DOM node
* new API `findNodeAtOffset`: Finds the most inner node at the given offset. If `includeRightBound` is set, also finds nodes that end at the given offset.

1.0.3 2018-03-07
==================
* provide ems modules

1.0.2 2018-03-05
==================
* added the *visit.onComment* API, reported when comments are allowed.
* added the *ParseErrorCode.InvalidCommentToken* enum value, reported when comments are disallowed.
* added the `visit.onComment` API, reported when comments are allowed.
* added the `ParseErrorCode.InvalidCommentToken` enum value, reported when comments are disallowed.

1.0.1
==================
* added the *format* API: computes edits to format a JSON document.
* added the *modify* API: computes edits to insert, remove or replace a property or value in a JSON document.
* added the *allyEdits* API: applies edits to a document
* added the `format` API: computes edits to format a JSON document.
* added the `modify` API: computes edits to insert, remove or replace a property or value in a JSON document.
* added the `allyEdits` API: applies edits to a document

1.0.0
==================
* remove nls dependency (remove getParseErrorMessage)
* remove nls dependency (remove `getParseErrorMessage`)

0.4.2 / 2017-05-05
==================
* added ParseError.offset & ParseError.length
* added `ParseError.offset` & `ParseError.length`

0.4.1 / 2017-04-02
==================
* added ParseOptions.allowTrailingComma
* added `ParseOptions.allowTrailingComma`

0.4.0 / 2017-02-23
==================
Expand Down
36 changes: 18 additions & 18 deletions src/impl/edit.ts
Expand Up @@ -4,15 +4,15 @@
*--------------------------------------------------------------------------------------------*/
'use strict';

import { Edit, FormattingOptions, ParseError, Node, JSONPath, Segment } from '../main';
import { Edit, ParseError, Node, JSONPath, Segment, ModificationOptions } from '../main';
import { format, isEOL } from './format';
import { parseTree, findNodeAtLocation } from './parser';

export function removeProperty(text: string, path: JSONPath, formattingOptions: FormattingOptions): Edit[] {
return setProperty(text, path, void 0, formattingOptions);
export function removeProperty(text: string, path: JSONPath, options: ModificationOptions): Edit[] {
return setProperty(text, path, void 0, options);
}

export function setProperty(text: string, originalPath: JSONPath, value: any, formattingOptions: FormattingOptions, getInsertionIndex?: (properties: string[]) => number, isArrayInsertion: boolean = false): Edit[] {
export function setProperty(text: string, originalPath: JSONPath, value: any, options: ModificationOptions): Edit[] {
let path = originalPath.slice()
let errors: ParseError[] = [];
let root = parseTree(text, errors);
Expand All @@ -38,7 +38,7 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
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);
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)) {
let existing = findNodeAtLocation(parent, [lastSegment]);
if (existing !== void 0) {
Expand All @@ -61,17 +61,17 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
removeEnd = next.offset;
}
}
return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: '' }, formattingOptions);
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) }, formattingOptions);
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
}
let newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
let index = getInsertionIndex ? getInsertionIndex(parent.children.map(p => p.children![0].value)) : parent.children.length;
let index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map(p => p.children![0].value)) : parent.children.length;
let edit: Edit;
if (index > 0) {
let previous = parent.children[index - 1];
Expand All @@ -81,7 +81,7 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
} else {
edit = { offset: parent.offset + 1, length: 0, content: newProperty + ',' };
}
return withFormatting(text, edit, formattingOptions);
return withFormatting(text, edit, options);
}
} else if (parent.type === 'array' && typeof lastSegment === 'number' && Array.isArray(parent.children)) {
let insertIndex = lastSegment;
Expand All @@ -95,7 +95,7 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
let previous = parent.children[parent.children.length - 1];
edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
}
return withFormatting(text, edit, formattingOptions);
return withFormatting(text, edit, options);
} else if (value === void 0 && parent.children.length >= 0) {
// Removal
let removalIndex = lastSegment;
Expand All @@ -113,12 +113,12 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
} else {
edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: '' };
}
return withFormatting(text, edit, formattingOptions);
return withFormatting(text, edit, options);
} else if (value !== void 0) {
let edit: Edit;
const newProperty = `${JSON.stringify(value)}`;

if (!isArrayInsertion && parent.children.length > lastSegment) {
if (!options.isArrayInsertion && parent.children.length > lastSegment) {
let toModify = parent.children[lastSegment];

edit = { offset: toModify.offset, length: toModify.length, content: newProperty }
Expand All @@ -130,18 +130,18 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
edit = { offset: previous.offset + previous.length, length: 0, content: ',' + newProperty };
}

return withFormatting(text, edit, formattingOptions);
return withFormatting(text, edit, options);
} else {
throw new Error(`Can not ${value === void 0 ? 'remove' : (isArrayInsertion ? 'insert' : 'modify')} Array index ${insertIndex} as length is not sufficient`);
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: string, edit: Edit, formattingOptions: FormattingOptions): Edit[] {
if (formattingOptions.inPlace) {
return [{ ...edit }]
function withFormatting(text: string, edit: Edit, options: ModificationOptions): Edit[] {
if (!options.formattingOptions) {
return [edit]
}
// apply the edit
let newText = applyEdit(text, edit);
Expand All @@ -158,7 +158,7 @@ function withFormatting(text: string, edit: Edit, formattingOptions: FormattingO
}
}

let edits = format(newText, { offset: begin, length: end - begin }, formattingOptions);
let 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 (let i = edits.length - 1; i >= 0; i--) {
Expand Down
11 changes: 3 additions & 8 deletions src/main.ts
Expand Up @@ -322,11 +322,6 @@ export interface FormattingOptions {
* The default 'end of line' character. If not set, '\n' is used as default.
*/
eol?: string;
/**
* If true, changes within {@function format} will not be formatted and their original formatting will be preserved.
* Useful for cutting down on computational time for large files.
*/
inPlace?: boolean;
}

/**
Expand All @@ -350,9 +345,9 @@ export function format(documentText: string, range: Range | undefined, options:
*/
export interface ModificationOptions {
/**
* Formatting options
* Formatting options. If undefined, the newly inserted code will be inserted unformatted.
*/
formattingOptions: FormattingOptions;
formattingOptions?: FormattingOptions;
/**
* Default false. If `JSONPath` refers to an index of an array and {@property isArrayInsertion} is `true`, then
* {@function modify} will insert a new item at that location instead of overwriting its contents.
Expand Down Expand Up @@ -380,7 +375,7 @@ export interface ModificationOptions {
* To apply edits to an input, you can use `applyEdits`.
*/
export function modify(text: string, path: JSONPath, value: any, options: ModificationOptions): Edit[] {
return edit.setProperty(text, path, value, options.formattingOptions, options.getInsertionIndex, options.isArrayInsertion);
return edit.setProperty(text, path, value, options);
}

/**
Expand Down

0 comments on commit f53c7ba

Please sign in to comment.