mirror of https://github.com/ghostfolio/ghostfolio
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.
109 lines
3.2 KiB
109 lines
3.2 KiB
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ChangeType = void 0;
|
|
exports.applyChangesToString = applyChangesToString;
|
|
var ChangeType;
|
|
(function (ChangeType) {
|
|
ChangeType["Delete"] = "Delete";
|
|
ChangeType["Insert"] = "Insert";
|
|
})(ChangeType || (exports.ChangeType = ChangeType = {}));
|
|
/**
|
|
* Applies a list of changes to a string's original value.
|
|
*
|
|
* This is useful when working with ASTs.
|
|
*
|
|
* For Example, to rename a property in a method's options:
|
|
*
|
|
* ```typescript
|
|
* const code = `bootstrap({
|
|
* target: document.querySelector('#app')
|
|
* })`;
|
|
*
|
|
* const indexOfPropertyName = 13; // Usually determined by analyzing an AST.
|
|
* const updatedCode = applyChangesToString(code, [
|
|
* {
|
|
* type: ChangeType.Insert,
|
|
* index: indexOfPropertyName,
|
|
* text: 'element'
|
|
* },
|
|
* {
|
|
* type: ChangeType.Delete,
|
|
* start: indexOfPropertyName,
|
|
* length: 6
|
|
* },
|
|
* ]);
|
|
*
|
|
* bootstrap({
|
|
* element: document.querySelector('#app')
|
|
* });
|
|
* ```
|
|
*/
|
|
function applyChangesToString(text, changes) {
|
|
assertChangesValid(changes);
|
|
const sortedChanges = changes.sort((a, b) => {
|
|
const diff = getChangeIndex(a) - getChangeIndex(b);
|
|
if (diff === 0) {
|
|
if (a.type === b.type) {
|
|
return 0;
|
|
}
|
|
else {
|
|
// When at the same place, Insert before Delete
|
|
return isStringInsertion(a) ? -1 : 1;
|
|
}
|
|
}
|
|
return diff;
|
|
});
|
|
let offset = 0;
|
|
for (const change of sortedChanges) {
|
|
const index = getChangeIndex(change) + offset;
|
|
if (isStringInsertion(change)) {
|
|
text = text.slice(0, index) + change.text + text.slice(index);
|
|
offset += change.text.length;
|
|
}
|
|
else {
|
|
text = text.slice(0, index) + text.slice(index + change.length);
|
|
offset -= change.length;
|
|
}
|
|
}
|
|
return text;
|
|
}
|
|
function assertChangesValid(changes) {
|
|
for (const change of changes) {
|
|
if (isStringInsertion(change)) {
|
|
if (!Number.isInteger(change.index)) {
|
|
throw new TypeError(`${change.index} must be an integer.`);
|
|
}
|
|
if (change.index < 0) {
|
|
throw new Error(`${change.index} must be a positive integer.`);
|
|
}
|
|
if (typeof change.text !== 'string') {
|
|
throw new Error(`${change.text} must be a string.`);
|
|
}
|
|
}
|
|
else {
|
|
if (!Number.isInteger(change.start)) {
|
|
throw new TypeError(`${change.start} must be an integer.`);
|
|
}
|
|
if (change.start < 0) {
|
|
throw new Error(`${change.start} must be a positive integer.`);
|
|
}
|
|
if (!Number.isInteger(change.length)) {
|
|
throw new TypeError(`${change.length} must be an integer.`);
|
|
}
|
|
if (change.length < 0) {
|
|
throw new Error(`${change.length} must be a positive integer.`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function getChangeIndex(change) {
|
|
if (isStringInsertion(change)) {
|
|
return change.index;
|
|
}
|
|
else {
|
|
return change.start;
|
|
}
|
|
}
|
|
function isStringInsertion(change) {
|
|
return change.type === ChangeType.Insert;
|
|
}
|
|
|